<?php
/**
 * Prompt Assembler for wizard-driven prompt construction.
 *
 * Assembles rich, Markdown+XML hybrid prompts from wizard form values
 * based on a generator's schema. Produces either full (system + user)
 * or additional-only prompts depending on the schema's prompt_mode.
 *
 * @package AIPT\Api\PromptBuilder
 */

namespace AIPT\Api\PromptBuilder;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class PromptAssembler {

	/**
	 * Schema registry dependency.
	 *
	 * @var WizardSchemaRegistry
	 */
	private $registry;

	public function __construct( WizardSchemaRegistry $registry ) {
		$this->registry = $registry;
	}

	/**
	 * Assemble a prompt from wizard state.
	 *
	 * @param string $generator_type Generator type.
	 * @param array  $step_values    Map of step_key => value (string or array).
	 * @return array{
	 *     system_prompt: string,
	 *     user_prompt: string,
	 *     additional_prompt: string,
	 *     preview_text: string
	 * }
	 */
	public function assemble( string $generator_type, array $step_values ): array {
		$schema = $this->registry->get_schema( $generator_type );
		$clean  = $this->sanitizeValues( $schema, $step_values );

		if ( 'full' === $schema['prompt_mode'] ) {
			$system     = $this->buildSystemPrompt( $schema, $clean );
			$user       = $this->buildUserPrompt( $schema, $clean );
			$additional = '';
		} else {
			$system     = '';
			$user       = '';
			$additional = $this->buildAdditionalPrompt( $schema, $clean );
		}

		$preview = $this->buildPreviewText( $schema, $clean );

		return array(
			'system_prompt'     => $system,
			'user_prompt'       => $user,
			'additional_prompt' => $additional,
			'preview_text'      => $preview,
		);
	}

	private function buildSystemPrompt( array $schema, array $values ): string {
		$lines         = array();
		$tones         = $this->getArrayValue( $values, 'writing_tone' );
		$audiences     = $this->getArrayValue( $values, 'target_audience' );
		$age_focus     = $this->getStringValue( $values, 'age_focus' );
		$goals         = $this->getArrayValue( $values, 'content_goals' );
		$writing_style = $this->getStringValue( $values, 'writing_style' );
		$format_style  = $this->getStringValue( $values, 'format_style' );
		$length        = $this->getStringValue( $values, 'content_length' );
		$language      = $this->getStringValue( $values, 'language' );
		$custom_prompt_vars = $this->getStringValue( $values, 'custom_prompt_variables' );
		$special       = $this->getStringValue( $values, 'special_instructions' );

		$lines[] = '<role>';
		$lines[] = 'You are a senior e-commerce copywriter with 10+ years of experience writing high-converting product content for online stores. You specialize in transforming product features into compelling customer benefits that drive purchase decisions.';
		$lines[] = '';
		$lines[] = 'Your expertise:';
		$lines[] = '- Converting technical specifications into emotional benefits';
		$lines[] = '- Writing SEO-optimized copy that ranks and converts';
		$lines[] = '- Crafting content that matches specific brand voices';
		$lines[] = '- Understanding buyer psychology and purchase triggers';
		$lines[] = '- Adapting product messaging for ' . $this->getIdentityForType( $schema['generator_type'] ) . ' outputs without losing factual accuracy';
		$lines[] = '</role>';
		$lines[] = '';

		$lines[] = '<tone_and_voice>';
		if ( ! empty( $tones ) ) {
			$lines[] = 'Selected tones: ' . implode( ', ', $tones ) . '.';
			$lines[] = $this->getToneGuidance( $tones );
		} else {
			$lines[] = 'Use a commercially persuasive tone that is clear, credible, and easy to trust.';
		}
		if ( '' !== $writing_style ) {
			$lines[] = 'Writing style to preserve: ' . $writing_style . '.';
		}
		if ( '' !== $format_style ) {
			$lines[] = 'Format preference to support: ' . $format_style . '.';
		}
		$lines[] = '</tone_and_voice>';
		$lines[] = '';

		$lines[] = '<target_audience>';
		$lines[] = $this->getAudienceGuidance( $audiences, $age_focus );
		$lines[] = '</target_audience>';
		$lines[] = '';

		$lines[] = '<content_goals>';
		$lines[] = $this->getGoalGuidance( $goals, $schema['generator_type'], $length );
		$lines[] = '</content_goals>';
		$lines[] = '';

		$lines[] = '<rules>';
		$lines[] = 'CONTENT RULES:';
		$lines[] = '- Output ONLY the requested content — no preamble, no meta-commentary, and no "Here is" introduction';
		$lines[] = '- Use HTML markup (<p>, <ul>, <li>, <strong>, <h3>) — NEVER use markdown syntax (no #, *, **, or code fences)';
		$lines[] = '- Focus on THIS product only — do not reference, compare to, or mention other products';
		$lines[] = '- Do not fabricate facts, certifications, specifications, or claims not present in product data';
		$lines[] = '- Write for humans first, search engines second — avoid keyword stuffing and robotic repetition';
		$lines[] = '';
		$lines[] = 'ANTI-SLOP RULES:';
		$lines[] = '- NEVER use these overused AI words: delve, tapestry, testament, vibrant, intricate, pivotal, underscore, robust, seamless, harness, leverage, unlock, empower, elevate, embark, revolutionize, game-changing, groundbreaking, state-of-the-art, cutting-edge';
		$lines[] = '- NEVER use these filler phrases: Its worth noting that, In todays world, When it comes to, A wide range of, Its important to note, Lets dive in, Not just X, but Y';
		$lines[] = '- NEVER use excessive em dashes (maximum 1 per paragraph)';
		$lines[] = '- Every sentence must add new information — do not restate the same point with different wording';
		$lines[] = '';
		$lines[] = 'CONVERSION RULES:';
		$lines[] = '- Lead with benefits, not features — transform specs into shopper outcomes';
		$lines[] = '- Use "you" language whenever it sounds natural and credible';
		$lines[] = '- Include specific details such as numbers, materials, dimensions, or use cases when they are present in the data';
		$lines[] = '- End with a clear, single call-to-action';

		$extra_rules = $this->getRulesForType( $schema['generator_type'] );
		if ( ! empty( $extra_rules ) ) {
			$lines[] = '';
			$lines[] = 'TYPE-SPECIFIC RULES:';
			foreach ( $extra_rules as $rule ) {
				$lines[] = '- ' . $rule;
			}
		}
		$lines[] = '</rules>';
		$lines[] = '';

		if ( '' !== $custom_prompt_vars ) {
			$lines[] = '<custom_variable_instructions>';
			$lines[] = 'The following instructions contain product variable placeholders (e.g., {title}, {PRICE}).';
			$lines[] = 'These will be replaced with actual product data. Use them as-is in your output context:';
			$lines[] = $custom_prompt_vars;
			$lines[] = '</custom_variable_instructions>';
			$lines[] = '';
		}

		if ( '' !== $special ) {
			$lines[] = '<additional_instructions>';
			$lines[] = $special;
			$lines[] = '</additional_instructions>';
			$lines[] = '';
		}

		$lines[] = '<quality_gate>';
		$lines[] = 'Before returning your final output, verify:';
		$lines[] = '1. Every claim is supported by product data — no fabricated specifications or promises';
		$lines[] = '2. The tone consistently matches the requested voice throughout';
		$lines[] = '3. Output uses ONLY HTML markup — search for and remove any markdown syntax';
		$lines[] = '4. Content stays within the requested length range' . ( '' !== $length ? ': ' . $this->describeLength( $length ) : '' ) . '.';
		$lines[] = '5. The opening sentence would make a shopper stop scrolling';
		$lines[] = '6. Benefits outnumber features in the copy';
		$lines[] = '7. Reads naturally in ' . ( '' !== $language ? $language : 'the target language' ) . ' with no awkward translation artifacts';
		$lines[] = '8. No words from the anti-slop banned list are present';
		foreach ( $this->getTypeSpecificQualityGate( $schema['generator_type'] ) as $index => $line ) {
			$lines[] = (string) ( $index + 9 ) . '. ' . $line;
		}
		$lines[] = '</quality_gate>';

		return implode( "\n", $lines );
	}

	private function buildUserPrompt( array $schema, array $values ): string {
		$lines = array();

		$keywords = $this->getArrayValue( $values, 'keywords' );
		$facts    = $this->getArrayValue( $values, 'interesting_facts' );

		$lines[] = '<task>';
		$lines[] = $this->getTaskForType( $schema['generator_type'], $values );
		$lines[] = '</task>';
		$lines[] = '';

		$lines[] = '<product_data>';
		$lines[] = '{product_data}';
		$lines[] = '</product_data>';
		$lines[] = '';

		if ( ! empty( $keywords ) ) {
			$lines[] = '<keywords>';
			$lines[] = 'Incorporate these keywords naturally (never force them): ' . implode( ', ', $keywords );
			$lines[] = '</keywords>';
			$lines[] = '';
		}

		if ( ! empty( $facts ) ) {
			$lines[] = '<interesting_facts>';
			$lines[] = 'Highlight these interesting facts where relevant:';
			foreach ( $facts as $fact ) {
				$lines[] = '- ' . $fact;
			}
			$lines[] = '</interesting_facts>';
			$lines[] = '';
		}

		$lines[] = '<reasoning>';
		$lines[] = 'Before writing, analyze:';
		$lines[] = '1. What unique value proposition does this product have based on the data?';
		$lines[] = '2. Who would buy this and what problem does it solve for them?';
		$lines[] = '3. Which 3 features translate into the strongest benefits?';
		$lines[] = '4. What emotional hook would stop a shopper from scrolling?';
		$lines[] = 'Then write the content based on your analysis.';
		$lines[] = '</reasoning>';
		$lines[] = '';

		$lines[] = '<output_format>';
		$lines[] = $this->getOutputFormatForType( $schema['generator_type'], $values );
		$lines[] = '</output_format>';

		return implode( "\n", $lines );
	}

	private function buildAdditionalPrompt( array $schema, array $values ): string {
		$lines     = array();
		$tones     = $this->getArrayValue( $values, 'writing_tone' );
		$audiences = $this->getArrayValue( $values, 'target_audience' );
		$keywords  = $this->getArrayValue( $values, 'keywords' );
		$language  = $this->getStringValue( $values, 'language' );
		$custom_prompt_vars = $this->getStringValue( $values, 'custom_prompt_variables' );
		$special   = $this->getStringValue( $values, 'special_instructions' );

		$lines[] = '<task>';
		$lines[] = $this->getTaskForType( $schema['generator_type'], $values );
		$lines[] = '</task>';
		$lines[] = '';

		$lines[] = '<additional_guidance>';
		$lines[] = '<voice>';
		if ( ! empty( $tones ) ) {
			$lines[] = 'Tone: ' . implode( ', ', $tones ) . ' — ' . $this->getToneGuidance( $tones );
		} else {
			$lines[] = 'Tone: commercially persuasive, natural, and credible.';
		}
		if ( ! empty( $audiences ) ) {
			$lines[] = 'Target audience: ' . implode( ', ', $audiences ) . '.';
			$lines[] = $this->getAudienceGuidance( $audiences, '' );
		} else {
			$lines[] = 'Target audience: shoppers evaluating whether this product solves a clear problem or fulfills a strong desire.';
		}
		$lines[] = '</voice>';
		$lines[] = '';
		$lines[] = '<constraints>';
		foreach ( $this->getAdditionalSpecs( $schema['generator_type'], $values ) as $line ) {
			$lines[] = $line;
		}
		$lines[] = '</constraints>';
		$lines[] = '';
		$lines[] = '<keywords>';
		$lines[] = ! empty( $keywords ) ? 'Incorporate naturally: ' . implode( ', ', $keywords ) : 'Use any available category, product, or intent keywords only when they fit naturally.';
		$lines[] = '</keywords>';
		$lines[] = '';
		$lines[] = '<anti_slop>';
		$lines[] = 'Avoid: delve, tapestry, testament, vibrant, leverage, unlock, empower, elevate, game-changing, groundbreaking, state-of-the-art, Its worth noting, In todays world.';
		$lines[] = '</anti_slop>';
		$lines[] = '';
		$lines[] = '<language>';
		$lines[] = 'All output in ' . ( '' !== $language ? $language : 'the requested language' ) . '. Adapt idioms and cultural references for the target market.';
		$lines[] = '</language>';
		if ( '' !== $special ) {
			$lines[] = '';
			$lines[] = '<special_instructions>';
			$lines[] = $special;
			$lines[] = '</special_instructions>';
		}
		if ( '' !== $custom_prompt_vars ) {
			$lines[] = '';
			$lines[] = '<custom_variable_instructions>';
			$lines[] = $custom_prompt_vars;
			$lines[] = '</custom_variable_instructions>';
		}
		$lines[] = '</additional_guidance>';
		$lines[] = '';

		$lines[] = '<reasoning>';
		$lines[] = 'Before writing, analyze:';
		$lines[] = '1. What matters most to a shopper searching for this product or category?';
		$lines[] = '2. Which benefit or keyword deserves the first line?';
		$lines[] = '3. Which objections, questions, or decision triggers should be addressed?';
		$lines[] = '4. Which concrete details make the output more trustworthy and clickable?';
		$lines[] = 'Then produce the final answer only.';
		$lines[] = '</reasoning>';
		$lines[] = '';

		$lines[] = '<output_format>';
		$lines[] = $this->getOutputFormatForType( $schema['generator_type'], $values );
		$lines[] = '</output_format>';
		$lines[] = '';

		$lines[] = '<quality_gate>';
		$lines[] = 'Before returning the final output, verify:';
		$lines[] = '1. Every statement is grounded in available data or common shopper intent for the requested output';
		$lines[] = '2. The output respects every length, count, or format constraint';
		$lines[] = '3. The primary keyword or benefit is front-loaded where appropriate';
		$lines[] = '4. The language reads naturally for ' . ( '' !== $language ? $language : 'the target market' ) . ' with no translation artifacts';
		$lines[] = '5. No banned anti-slop wording appears';
		foreach ( $this->getTypeSpecificQualityGate( $schema['generator_type'] ) as $index => $line ) {
			$lines[] = (string) ( $index + 6 ) . '. ' . $line;
		}
		$lines[] = '</quality_gate>';

		return implode( "\n", $lines );
	}

	private function buildPreviewText( array $schema, array $values ): string {
		$parts   = array();
		$parts[] = sprintf( '[%s]', $schema['label'] );

		foreach ( $schema['steps'] as $step ) {
			if ( 'review' === $step['type'] ) {
				continue;
			}

			$v = $values[ $step['key'] ] ?? null;
			if ( null === $v || '' === $v || ( is_array( $v ) && 0 === count( $v ) ) ) {
				continue;
			}

			$display = is_array( $v ) ? implode( ', ', $v ) : (string) $v;
			$parts[] = $step['label'] . ': ' . $display;
		}

		return implode( "\n", $parts );
	}

	private function getIdentityForType( string $type ): string {
		$map = array(
			'description' => 'product description',
			'standard'    => 'product description',
			'title'       => 'product title',
			'faq'         => 'product FAQ',
			'seo_meta'    => 'SEO meta',
			'taxonomy'    => 'taxonomy (category/tag)',
		);

		return $map[ $type ] ?? 'content';
	}

	private function getTaskForType( string $type, array $values = array() ): string {
		switch ( $type ) {
			case 'description':
				return 'Write a compelling, conversion-focused product description. Open with a hook that addresses the customer\'s need. Transform every feature into a customer benefit. Structure: opening hook → key benefits → feature details → call-to-action.';
			case 'standard':
				return 'Write a clear, scannable product description optimized for quick reading. Lead with the primary benefit. Use short paragraphs (2-3 sentences max) and bullet points for features.';
			case 'title':
				$character_limit = $this->getStringValue( $values, 'character_limit' );
				return 'Generate an SEO-optimized product title that leads with the primary customer benefit. The title must be under ' . ( '' !== $character_limit ? $character_limit : 'the requested' ) . ' characters and include the primary keyword within the first 5 words.';
			case 'faq':
				$faq_count = $this->getStringValue( $values, 'faq_count' );
				return 'Generate exactly ' . ( '' !== $faq_count ? $faq_count : 'the requested number of' ) . ' frequently asked questions with detailed answers about this product. Questions should address real customer concerns: what it does, who it\'s for, specifications, shipping, and common objections.';
			case 'seo_meta':
				$title_limit = $this->getStringValue( $values, 'meta_title_limit' );
				$desc_limit  = $this->getStringValue( $values, 'meta_desc_limit' );
				return 'Generate an SEO meta title (max ' . ( '' !== $title_limit ? $title_limit : 'the requested' ) . ' chars) and meta description (max ' . ( '' !== $desc_limit ? $desc_limit : 'the requested' ) . ' chars). The meta title must front-load the primary keyword. The meta description must start with the keyword and end with a clear call-to-action.';
			case 'taxonomy':
				$purpose       = $this->getStringValue( $values, 'purpose' );
				$taxonomy_type = 'taxonomy';
				return 'Write a ' . ( '' !== $purpose ? $purpose : 'taxonomy description' ) . ' for this ' . $taxonomy_type . ' that helps shoppers understand what products belong in this category and why they should browse it.';
			default:
				return 'Generate content based on the provided product data.';
		}
	}

	private function getRulesForType( string $type ): array {
		switch ( $type ) {
			case 'description':
				return array(
					'Structure with clear sections: opening hook, key benefits, feature details, closing CTA.',
					'Use <h3> for section headers, <ul> for benefit lists, and <strong> to emphasize decision-driving details.',
					'Lead the first paragraph with the shopper outcome, not a neutral product summary.',
				);
			case 'standard':
				return array(
					'Keep structure simple and skimmable with short paragraphs and a short bulleted list.',
					'Front-load the strongest benefit in the first sentence and keep every paragraph focused on one idea.',
				);
			case 'title':
				return array(
					'Lead with the primary benefit.',
					'Include the primary keyword in the first 5 words.',
					'Use active voice and remove filler words that waste character count.',
				);
			case 'faq':
				return array(
					'Each answer must be under 100 words.',
					'Questions must be written in natural language that mirrors real shopper concerns.',
					'Answers must reference specific product features, materials, use cases, or purchase details when available.',
				);
			case 'seo_meta':
				return array(
					'Meta title: front-load the keyword.',
					'Meta description: start with the keyword and end with a call-to-action.',
					'Both meta fields must be complete, natural-sounding sentences or sentence fragments suitable for SERPs.',
				);
			case 'taxonomy':
				return array(
					'Describe what products belong in this category or term.',
					'Include buyer intent so shoppers understand who the category is for and why it matters.',
					'Mention 2-3 example product types when the data supports it.',
				);
			default:
				return array();
		}
	}

	private function getAdditionalSpecs( string $type, array $values ): array {
		$lines = array();

		switch ( $type ) {
			case 'title':
				$limit = $this->getStringValue( $values, 'character_limit' );
				if ( '' !== $limit ) {
					$lines[] = 'Maximum ' . $limit . ' characters.';
				}

				$formula = $this->getStringValue( $values, 'title_formula' );
				if ( '' !== $formula ) {
					$lines[] = 'Structure: ' . $this->getFormulaDescription( $formula ) . '.';
				}
				$lines[] = 'Make the title feel click-worthy, precise, and commercially credible.';
				break;

			case 'faq':
				$count = $this->getStringValue( $values, 'faq_count' );
				if ( '' !== $count ) {
					$lines[] = 'Generate exactly ' . $count . ' Q&A pairs.';
				}

				$format = $this->getStringValue( $values, 'faq_format' );
				if ( '' !== $format ) {
					$lines[] = 'Format: ' . $this->getFaqFormatDescription( $format ) . '.';
				}
				$lines[] = 'Cover buying objections, use cases, compatibility, care, delivery, and value where relevant.';
				break;

			case 'seo_meta':
				$title_limit = $this->getStringValue( $values, 'meta_title_limit' );
				$desc_limit  = $this->getStringValue( $values, 'meta_desc_limit' );
				if ( '' !== $title_limit ) {
					$lines[] = 'Meta title max ' . $title_limit . ' characters.';
				}
				if ( '' !== $desc_limit ) {
					$lines[] = 'Meta description max ' . $desc_limit . ' characters.';
				}

				$focus = $this->getStringValue( $values, 'seo_focus' );
				if ( '' !== $focus ) {
					$lines[] = 'SEO focus: ' . $this->getSeoFocusDescription( $focus ) . '.';
				}
				$lines[] = 'Each field should increase click-through rate without sounding spammy.';
				break;

			case 'taxonomy':
				$purpose = $this->getStringValue( $values, 'purpose' );
				$length  = $this->getStringValue( $values, 'content_length' );
				if ( '' !== $purpose ) {
					$lines[] = 'Purpose: ' . $this->getPurposeDescription( $purpose ) . '.';
				}
				if ( '' !== $length ) {
					$lines[] = 'Length target: ' . $this->describeLength( $length ) . '.';
				}
				$lines[] = 'Clarify the category promise, shopper intent, and the kinds of products people can expect to find.';
				break;
		}

		return $lines;
	}

	private function getOutputFormatForType( string $type, array $values = array() ): string {
		switch ( $type ) {
			case 'description':
				return 'Structure as: <p>[opening hook]</p> <h3>[benefits header]</h3> <ul><li>[3-5 benefit items]</li></ul> <p>[closing CTA]</p>. Use <strong> for key terms.';
			case 'standard':
				return '<p>[2-3 short paragraphs]</p> <ul><li>[3-5 quick bullet points]</li></ul>';
			case 'title':
				$character_limit = $this->getStringValue( $values, 'character_limit' );
				return 'Plain text. Single line. No HTML tags. No quotes around the title.' . ( '' !== $character_limit ? ' Stay under ' . $character_limit . ' characters.' : '' );
			case 'faq':
				$faq_count = $this->getStringValue( $values, 'faq_count' );
				return 'Format each Q&A as: <h4>[Question]</h4><p>[Answer]</p>. Do NOT number the questions.' . ( '' !== $faq_count ? ' Return exactly ' . $faq_count . ' questions.' : '' );
			case 'seo_meta':
				$title_limit = $this->getStringValue( $values, 'meta_title_limit' );
				$desc_limit  = $this->getStringValue( $values, 'meta_desc_limit' );
				return 'Return as JSON: {"meta_title": "...", "meta_description": "..."}. No HTML.' . ( '' !== $title_limit || '' !== $desc_limit ? ' Respect the configured character limits for both fields.' : '' );
			case 'taxonomy':
				$length = $this->getStringValue( $values, 'content_length' );
				return '<p>[2-3 paragraphs describing the category]</p>' . ( '' !== $length ? ' Match the ' . $this->describeLength( $length ) . ' target.' : '' );
			default:
				return 'Plain text unless otherwise specified.';
		}
	}

	private function describeLength( string $length ): string {
		$map = array(
			'short'  => 'Short (50-100 words)',
			'medium' => 'Medium (100-250 words)',
			'long'   => 'Long (250-500 words)',
		);

		return $map[ $length ] ?? $length;
	}

	private function getToneGuidance( array $tones ): string {
		$hints = array(
			'professional'  => 'Maintain polished, commercially credible language with clear sentence structure. Sound confident and competent without becoming stiff or corporate. Prioritize clarity, trust, and strong purchase logic.',
			'friendly'      => 'Write like a helpful expert having a warm one-to-one conversation. Keep the language approachable, encouraging, and easy to follow. Make the shopper feel guided rather than sold to.',
			'casual'        => 'Use relaxed, everyday wording that feels natural and low-pressure. Keep the rhythm smooth and conversational without becoming sloppy. Make the product feel easy to understand and easy to say yes to.',
			'playful'       => 'Use lively phrasing, tasteful personality, and light charm without turning the copy into a joke. Keep the product benefits clear while adding energy and memorability. Make the tone feel fun but still conversion-focused.',
			'luxurious'     => 'Emphasize refinement, craftsmanship, exclusivity, and sensory appeal. Use elegant language that suggests premium value without exaggeration. Make the reader feel they are investing in something exceptional.',
			'authoritative' => 'Sound like a category expert who knows exactly what matters. Use decisive language, strong judgment, and high informational confidence. Remove hedging and make each claim feel grounded and assured.',
			'witty'         => 'Use clever turns of phrase sparingly to create memorability and charm. Keep the humor sharp, relevant, and easy to understand. Never let wordplay obscure the product value or core message.',
			'inspirational' => 'Focus on progress, possibility, and the positive change this product can create. Use language that lifts the shopper’s imagination while staying believable. Make the product feel like a step toward a better outcome.',
			'empathetic'    => 'Show clear understanding of the shopper’s frustrations, needs, and hesitations. Use reassuring wording that makes the reader feel seen and supported. Position the product as a thoughtful solution, not a hard sell.',
			'bold'          => 'Use punchy, high-conviction language with strong verbs and decisive statements. Keep the copy assertive and high-energy without sounding aggressive. Make the main benefit impossible to miss.',
			'minimalist'    => 'Use clean, concise language with high informational density. Strip out filler, repetition, and decorative phrasing. Let precise word choice and strong structure create the impact.',
			'enthusiastic'  => 'Let genuine excitement show through energetic but controlled language. Make benefits feel vivid, immediate, and worth acting on. Keep the enthusiasm credible by tying it to concrete product details.',
			'elegant'       => 'Write with grace, polish, and refined restraint. Favor smooth phrasing, selective detail, and a premium cadence. Make the copy feel sophisticated without becoming distant.',
			'technical'     => 'Use precise, specification-aware language that respects informed buyers. Explain what the details mean in practical terms rather than listing specs without context. Stay exact, factual, and free from hype.',
			'conversational' => 'Write in a natural spoken rhythm that feels human and direct. Use smooth transitions and clear logic instead of formal presentation. Make the copy sound like smart advice from someone who knows the product well.',
			'storytelling'  => 'Use narrative flow to help the shopper imagine a real scenario, need, or outcome. Build momentum from problem to payoff without drifting away from the product. Keep every story element tied to conversion.',
			'urgent'        => 'Create momentum with concise, action-oriented phrasing and a clear sense of immediacy. Highlight why acting now matters without using fake scarcity. Keep the pressure credible and benefit-led.',
			'calming'       => 'Use reassuring, steady language that lowers friction and reduces overwhelm. Make the copy feel clear, supportive, and easy to absorb. Emphasize confidence, comfort, and simplicity.',
			'edgy'          => 'Use daring, unconventional phrasing that feels modern and attention-grabbing. Keep the tone confident and sharp without becoming reckless or confusing. Make the product feel distinctive and culturally aware.',
			'nostalgic'     => 'Use subtle references to familiarity, comfort, and lasting appeal. Make the shopper feel an emotional connection without sounding dated. Tie the nostalgia back to present-day usefulness and desire.',
			'eco_conscious' => 'Highlight sustainability, responsible materials, and lower-impact choices with accuracy and restraint. Avoid vague green claims and only use eco language supported by the data. Make the environmental angle feel meaningful, not performative.',
			'youthful'      => 'Use fresh, energetic language that feels current and socially aware. Keep the tone confident, quick, and expressive without chasing slang too hard. Make the product feel relevant to modern lifestyles.',
			'sophisticated' => 'Write with cultured confidence and nuanced wording. Balance intelligence, taste, and restraint so the copy feels elevated but readable. Make every line feel intentional and well judged.',
			'direct'        => 'Say exactly what matters with no detours or fluff. Lead with the strongest point, explain the value fast, and keep every sentence purposeful. Make the buying decision feel simpler with each line.',
			'humorous'      => 'Use light, accessible humor that supports recall and likability. Keep jokes secondary to clarity, product truth, and conversion. The shopper should smile and still remember the main benefit.',
			'relaxed'       => 'Keep the pacing easy and pressure low while still being persuasive. Use calm, effortless phrasing that removes friction from the buying decision. Make the product feel approachable and easy to enjoy.',
			'happy'         => 'Use upbeat, optimistic language that creates a feel-good buying mood. Keep the positivity clean and natural rather than sugary. Make the product feel rewarding, satisfying, and easy to love.',
			'informative'   => 'Prioritize clarity, usefulness, and concrete understanding. Explain what the product does, who it suits, and why details matter. Make the shopper feel more informed and more confident to buy.',
			'emotional'     => 'Lead with feeling, desire, relief, or aspiration tied to the shopper’s real motivations. Keep the emotional angle grounded in believable outcomes. Make the product feel personally meaningful, not melodramatic.',
			'sincere'       => 'Use honest, straightforward wording that feels transparent and human. Avoid inflated claims and let credibility come from specificity and restraint. Make the brand sound trustworthy and genuine.',
			'quirky'        => 'Add distinctive personality and offbeat charm in a controlled way. Use unusual but understandable phrasing that makes the copy memorable. Keep the message useful and never let eccentricity disrupt clarity.',
			'inspiring'     => 'Use confident, future-facing language that helps the shopper imagine better outcomes. Connect the product to progress, aspiration, or momentum. Keep the inspiration actionable and product-led.',
			'confident'     => 'Write with certainty, decisiveness, and strong commercial clarity. Avoid timid phrasing and make the recommendation feel assured. Support the confidence with specific reasons the product deserves attention.',
			'trustworthy'   => 'Use transparent, balanced wording that feels dependable and stable. Favor specificity, realistic promises, and shopper-first clarity. Make the copy feel safe to believe.',
			'innovative'    => 'Position the product as modern, thoughtful, and meaningfully advanced. Focus on what is genuinely improved or smarter about the design. Make progress feel concrete, useful, and credible.',
			'sensational'   => 'Use vivid, high-impact language that amplifies excitement and desirability. Keep the drama controlled so it still feels premium rather than exaggerated. Make the most impressive benefits feel impossible to ignore.',
			'whimsical'     => 'Use imaginative, airy phrasing that adds delight and charm. Keep it light, visual, and emotionally warm without becoming vague. Make the product feel enchanting while staying understandable.',
			'timeless'      => 'Focus on enduring appeal, long-term usefulness, and classic confidence. Use elegant, uncluttered language that resists trends. Make the product feel relevant now and years from now.',
			'practical'     => 'Emphasize usefulness, reliability, ease, and real-life problem solving. Use grounded wording that respects budget, time, and functionality. Make the buying decision feel sensible and worthwhile.',
			'trendy'        => 'Use current, style-aware language that signals relevance and social momentum. Keep it sharp and modern without making the copy disposable or slang-heavy. Make the product feel timely and desirable right now.',
			'captivating'   => 'Hook attention early with magnetic, benefit-rich phrasing. Keep the copy immersive and compelling without becoming vague. Make each section pull the shopper smoothly to the next.',
			'intimate'      => 'Write with closeness, warmth, and a one-to-one sense of understanding. Make the shopper feel personally addressed and emotionally connected. Keep the tone soft, human, and specific.',
			'thoughtful'    => 'Use measured, considerate language that reflects care and intention. Show that the copy understands nuance, context, and buyer priorities. Make the product feel well designed and well chosen.',
			'exhilarating'  => 'Use dynamic, high-energy language that conveys momentum, thrill, and payoff. Keep the excitement tied to real use cases and outcomes. Make the product feel like an experience worth chasing.',
			'vibrant'       => 'Use vivid, energetic language with strong sensory texture and momentum. Keep the tone lively and expressive while staying precise and shopper-friendly. Make the copy feel full of life, not overdecorated.',
		);

		$matched = array();
		foreach ( $tones as $tone ) {
			$key = strtolower( str_replace( array( ' ', '-' ), '_', $tone ) );
			if ( isset( $hints[ $key ] ) ) {
				$matched[] = $hints[ $key ];
			}
		}

		return implode( ' ', $matched );
	}

	private function getAudienceGuidance( array $audiences, string $age_focus ): string {
		$parts = array();

		if ( ! empty( $audiences ) ) {
			$parts[] = 'Primary audience segments: ' . implode( ', ', $audiences ) . '.';
			$parts[] = 'Write for people evaluating whether this product fits their needs, budget, lifestyle, and expectations.';
			$parts[] = 'Address the motivations, hesitations, and desired outcomes implied by those audience segments.';
		} else {
			$parts[] = 'Assume the audience is comparison-shopping and needs a clear reason to care quickly.';
			$parts[] = 'Use buyer-aware language that explains who the product is for, why it matters, and what makes it worthwhile.';
		}

		if ( '' !== $age_focus ) {
			$parts[] = 'Age focus: ' . $age_focus . '. Adapt examples, priorities, and references so they feel relevant to that life stage.';
		}

		return implode( ' ', $parts );
	}

	private function getGoalGuidance( array $goals, string $type, string $length ): string {
		$parts = array();

		if ( ! empty( $goals ) ) {
			$parts[] = 'Prioritize these goals: ' . implode( ', ', $goals ) . '.';
			$parts[] = 'Balance conversion, clarity, SEO relevance, and buyer confidence based on those priorities.';
		} else {
			$parts[] = 'Primary goal: help the shopper understand the value fast and feel confident enough to act.';
		}

		$parts[] = 'Optimize for high intent e-commerce reading behavior: fast scanning, strong openings, concrete proof, and low-friction next steps.';
		if ( '' !== $length ) {
			$parts[] = 'Keep the output aligned with this length target: ' . $this->describeLength( $length ) . '.';
		}
		if ( 'description' === $type || 'standard' === $type ) {
			$parts[] = 'Make benefits more prominent than features and shape the structure for quick purchase evaluation.';
		}

		return implode( ' ', $parts );
	}

	private function getTypeSpecificQualityGate( string $type ): array {
		switch ( $type ) {
			case 'description':
				return array(
					'The closing section ends with one clear call-to-action.',
					'The copy includes 3-5 concrete benefit-led points rather than a wall of generic text.',
				);
			case 'standard':
				return array(
					'The copy is easy to scan with short paragraphs and concise bullets.',
					'The first sentence communicates the main benefit immediately.',
				);
			case 'title':
				return array(
					'The title stays within the character limit and uses active voice.',
					'The main keyword or benefit appears within the first 5 words.',
				);
			case 'faq':
				return array(
					'The requested number of FAQs is exact and every answer stays under 100 words.',
					'Questions sound natural and answers reference concrete product details where possible.',
				);
			case 'seo_meta':
				return array(
					'The response is valid JSON with exactly meta_title and meta_description keys.',
					'The meta title is front-loaded and the meta description starts with the keyword and ends with a CTA.',
				);
			case 'taxonomy':
				return array(
					'The copy explains what belongs in the category and why a shopper would browse it.',
					'The description reflects buyer intent and mentions example product types when supported.',
				);
			default:
				return array();
		}
	}

	private function getFormulaDescription( string $formula ): string {
		$map = array(
			'benefit_first' => 'lead with the strongest shopper benefit, then add the product type or defining detail',
			'feature_first' => 'open with the strongest concrete feature, then connect it to the customer outcome',
			'descriptive'   => 'combine the primary keyword with the most helpful descriptive qualifier',
			'brand_first'   => 'open with the brand only if it improves recognition, then move immediately into the main benefit or keyword',
			'question'      => 'use a question-style hook only if it remains concise, searchable, and product-specific',
		);

		return $map[ $formula ] ?? $formula;
	}

	private function getFaqFormatDescription( string $format ): string {
		$map = array(
			'text'            => 'plain text question and answer pairs with clean separation between each entry',
			'html'            => 'HTML question and answer pairs using shopper-friendly headings and paragraphs',
			'definition_list' => 'definition list style that keeps each question-answer pair tightly grouped and readable',
		);

		return $map[ $format ] ?? $format;
	}

	private function getSeoFocusDescription( string $focus ): string {
		$map = array(
			'keyword'    => 'prioritize exact-match or close-match keyword visibility without sounding forced',
			'benefit'    => 'emphasize the strongest customer outcome to improve click appeal',
			'question'   => 'frame the metadata around a shopper question or search intent pattern when natural',
			'comparison' => 'position the metadata for evaluative searches where shoppers are comparing options',
		);

		return $map[ $focus ] ?? $focus;
	}

	private function getPurposeDescription( string $purpose ): string {
		$map = array(
			'seo_description'       => 'SEO description that improves discoverability while helping shoppers understand category fit',
			'display_name'          => 'display name that is clear, intuitive, and aligned with shopper expectations',
			'marketing_description' => 'marketing description that sells the category promise and encourages browsing',
		);

		return $map[ $purpose ] ?? $purpose;
	}

	private function sanitizeValues( array $schema, array $values ): array {
		$clean = array();

		foreach ( $schema['steps'] as $step ) {
			if ( 'review' === $step['type'] ) {
				continue;
			}

			$key = $step['key'];
			$raw = $values[ $key ] ?? null;
			if ( null === $raw ) {
				continue;
			}

			switch ( $step['type'] ) {
				case 'textarea':
				case 'variables_textarea':
					$clean[ $key ] = sanitize_textarea_field( (string) $raw );
					break;

				case 'multi_select':
				case 'dynamic_array':
					if ( ! is_array( $raw ) ) {
						$clean[ $key ] = array();
						break;
					}

					$clean[ $key ] = array_values(
						array_filter(
							array_map(
								static function ( $value ) {
									return sanitize_text_field( (string) $value );
								},
								$raw
							),
							static function ( $value ) {
								return '' !== $value;
							}
						)
					);
					break;

				default:
					$clean[ $key ] = sanitize_text_field( (string) $raw );
			}
		}

		return $clean;
	}

	private function getStringValue( array $values, string $key ): string {
		$value = $values[ $key ] ?? '';
		if ( is_array( $value ) ) {
			return '';
		}

		return (string) $value;
	}

	private function getArrayValue( array $values, string $key ): array {
		$value = $values[ $key ] ?? array();
		if ( ! is_array( $value ) ) {
			return array();
		}

		return array_values(
			array_filter(
				$value,
				static function ( $item ) {
					return '' !== $item && null !== $item;
				}
			)
		);
	}
}
