<?php
/**
 * SEO Meta Prompt Factory
 *
 * Builds AI prompts for SEO meta generation using Markdown+XML hybrid structure.
 *
 * @package AIPT\Api\BulkGenerator\SeoMeta\Core
 */

namespace AIPT\Api\BulkGenerator\SeoMeta\Core;

use AIPT\Utils\PromptFormatter;

/**
 * Factory class for building SEO meta generation prompts.
 *
 * Uses Markdown+XML hybrid structure following v2.6.2 prompt engineering patterns.
 * Includes SEO-specific quality gates for character limits.
 *
 * @since 2.4.0
 */
class SeoMetaPromptFactory {

	/**
	 * Default character limits for SEO meta fields.
	 */
	private const TITLE_MAX_LENGTH = 60;
	private const DESC_MAX_LENGTH = 160;

	/**
	 * Patterns to detect and remove AI instruction injection attempts.
	 */
	public const INJECTION_PATTERNS = [
		'/```[\s\S]*?```/m',
		'/`[^`]*`/m',
		'/\b[A-Za-z0-9+\/]{100,}={0,2}\b/',
		'/ignore\s+(all\s+)?(previous|prior|above)\s+instructions?/i',
		'/disregard\s+(all\s+)?(previous|prior|above)/i',
		'/do\s+not\s+follow/i',
		'/forget\s+(everything|all|previous)/i',
		'/new\s+instructions?:/i',
		'/system\s*:\s*/i',
		'/\[\s*INST\s*\]/i',
		'/<\s*\|?\s*(system|assistant|user)\s*\|?\s*>/i',
		'/<\s*script[^>]*>.*?<\s*\/\s*script\s*>/is',
		'/<\s*style[^>]*>.*?<\s*\/\s*style\s*>/is',
		'/<\s*iframe[^>]*>.*?<\s*\/\s*iframe\s*>/is',
		'/<\s*\?php/i',
		'/<!--.*?-->/s',
	];

	/**
	 * Builds the system prompt for SEO meta generation.
	 *
	 * @param string $language The target language.
	 * @param array  $options  Generation options.
	 *
	 * @return string The system prompt.
	 */
	public function buildSystemPrompt( $language = 'English', $options = array() ) {
		$tone             = isset( $options['tone'] ) ? $options['tone'] : 'Professional';
		$title_max_length = isset( $options['titleMaxLength'] ) ? (int) $options['titleMaxLength'] : self::TITLE_MAX_LENGTH;
		$desc_max_length  = isset( $options['descMaxLength'] ) ? (int) $options['descMaxLength'] : self::DESC_MAX_LENGTH;
		$include_focus_kw = ! empty( $options['generateFocusKeyword'] );
		$optimize_for_kw  = ! empty( $options['optimizeForFocusKeyword'] );
		$generate_title   = isset( $options['generateTitle'] ) ? $options['generateTitle'] : true;
		$generate_desc    = isset( $options['generateDescription'] ) ? $options['generateDescription'] : true;

		$prompt_parts = array();

		$prompt_parts[] = $this->getIdentitySection();

		$prompt_parts[] = $this->getLanguageStyleSection( $language, $tone );

		$prompt_parts[] = $this->getCoreRulesSection( $title_max_length, $desc_max_length );

		if ( $include_focus_kw && $optimize_for_kw ) {
			$prompt_parts[] = $this->getKeywordOptimizationSection();
		}

		$prompt_parts[] = $this->getQualityGateSection( $title_max_length, $desc_max_length );

		$prompt_parts[] = $this->getOutputFormatSection( $include_focus_kw, $generate_title, $generate_desc );

		return PromptFormatter::cleanContent( implode( "\n\n", array_filter( $prompt_parts ) ) );
	}

	/**
	 * Builds the user prompt for SEO meta generation.
	 *
	 * @param array $product_data Product data array.
	 * @param array $options      Generation options.
	 *
	 * @return string The user prompt.
	 */
	public function buildUserPrompt( $product_data, $options = array() ) {
		$prompt_parts = array();

		$sources = isset( $options['sources'] ) && is_array( $options['sources'] )
			? $options['sources']
			: array( 'product_name', 'product_description', 'product_categories' );

		$prompt_parts[] = $this->getProductDataSection( $product_data, $sources );

		$current_meta = $this->getCurrentMetaSection( $product_data );
		if ( ! empty( $current_meta ) ) {
			$prompt_parts[] = $current_meta;
		}

		$prompt_parts[] = $this->getTaskSection( $options );

		return PromptFormatter::cleanContent( implode( "\n\n", array_filter( $prompt_parts ) ) );
	}

	/**
	 * Builds the system prompt for multi-variant SEO meta generation.
	 *
	 * @param string $language The target language.
	 * @param array  $options  Generation options including 'variantCount'.
	 *
	 * @return string The system prompt for variant generation.
	 */
	public function buildVariantSystemPrompt( $language = 'English', $options = array() ) {
		$tone             = isset( $options['tone'] ) ? $options['tone'] : 'Professional';
		$title_max_length = isset( $options['titleMaxLength'] ) ? (int) $options['titleMaxLength'] : self::TITLE_MAX_LENGTH;
		$desc_max_length  = isset( $options['descMaxLength'] ) ? (int) $options['descMaxLength'] : self::DESC_MAX_LENGTH;
		$include_focus_kw = ! empty( $options['generateFocusKeyword'] );
		$optimize_for_kw  = ! empty( $options['optimizeForFocusKeyword'] );
		$variant_count    = isset( $options['variantCount'] ) ? (int) $options['variantCount'] : 2;
		$generate_title   = isset( $options['generateTitle'] ) ? $options['generateTitle'] : true;
		$generate_desc    = isset( $options['generateDescription'] ) ? $options['generateDescription'] : true;

		$variant_count = max( 1, min( 5, $variant_count ) );

		$prompt_parts = array();

		$prompt_parts[] = $this->getIdentitySection();

		$prompt_parts[] = $this->getLanguageStyleSection( $language, $tone );

		$prompt_parts[] = $this->getCoreRulesSection( $title_max_length, $desc_max_length );

		if ( $include_focus_kw && $optimize_for_kw ) {
			$prompt_parts[] = $this->getKeywordOptimizationSection();
		}

		$prompt_parts[] = $this->getVariantRulesSection( $variant_count );

		$prompt_parts[] = $this->getQualityGateSection( $title_max_length, $desc_max_length );

		$prompt_parts[] = $this->getVariantOutputFormatSection( $include_focus_kw, $variant_count, $generate_title, $generate_desc );

		return PromptFormatter::cleanContent( implode( "\n\n", array_filter( $prompt_parts ) ) );
	}

	/**
	 * Builds the user prompt for multi-variant SEO meta generation.
	 *
	 * @param array $product_data Product data array.
	 * @param array $options      Generation options including 'variantCount'.
	 *
	 * @return string The user prompt for variant generation.
	 */
	public function buildVariantUserPrompt( $product_data, $options = array() ) {
		$prompt_parts = array();

		$sources = isset( $options['sources'] ) && is_array( $options['sources'] )
			? $options['sources']
			: array( 'product_name', 'product_description', 'product_categories' );

		$prompt_parts[] = $this->getProductDataSection( $product_data, $sources );

		$current_meta = $this->getCurrentMetaSection( $product_data );
		if ( ! empty( $current_meta ) ) {
			$prompt_parts[] = $current_meta;
		}

		$variant_count = isset( $options['variantCount'] ) ? (int) $options['variantCount'] : 2;

		$variant_count  = max( 1, min( 5, $variant_count ) );
		$prompt_parts[] = $this->getVariantTaskSection( $options, $variant_count );

		return PromptFormatter::cleanContent( implode( "\n\n", array_filter( $prompt_parts ) ) );
	}

	/**
	 * Builds the system prompt for focus keyword-only generation (Phase 1 of two-phase).
	 *
	 * @param string $language The target language.
	 * @param array  $options  Generation options.
	 *
	 * @return string The system prompt for keyword-only generation.
	 */
	public function buildKeywordOnlySystemPrompt( $language = 'English', $options = array() ) {
		$tone = isset( $options['tone'] ) ? $options['tone'] : 'Professional';

		return PromptFormatter::cleanContent( "# Identity
You are an expert SEO keyword researcher for e-commerce products. You identify the single best focus keyword that will maximize search visibility and conversion rates.

# Language & Style
- Language: {$language}
- Tone: {$tone}

# Keyword Selection Rules
1. Choose ONE focus keyword (1-3 words maximum).
2. The keyword should represent the primary search intent for this product.
3. Prioritize keywords with commercial/transactional intent over informational.
4. Consider what buyers would actually type into Google.
5. The keyword should be specific to this product, not overly generic.
6. If the product has a distinct feature or benefit, include it in the keyword.

# Quality Gate
Before finalizing, verify:
- Keyword is 1-3 words only
- Keyword is relevant to the product
- Keyword has commercial search intent
- Keyword is not too generic (e.g., \"shoes\" alone is too generic)

<output_format>
Return ONLY valid JSON with no additional text or explanation:
{\"focus_keyword\": \"your keyword here\"}
</output_format>" );
	}

	/**
	 * Builds the user prompt for focus keyword-only generation (Phase 1 of two-phase).
	 *
	 * @param array $product_data Product data array.
	 * @param array $options      Generation options.
	 *
	 * @return string The user prompt for keyword-only generation.
	 */
	public function buildKeywordOnlyUserPrompt( $product_data, $options = array() ) {
		$sources = isset( $options['sources'] ) && is_array( $options['sources'] )
			? $options['sources']
			: array( 'product_name', 'product_description', 'product_categories' );

		$prompt_parts   = array();
		$prompt_parts[] = $this->getProductDataSection( $product_data, $sources );

		$additional_instructions = $this->getAdditionalInstructionsSection( $options, $product_data );
		if ( $additional_instructions ) {
			$prompt_parts[] = $additional_instructions;
		}

		$prompt_parts[] = '<task>
Analyze this product and generate the single best focus keyword (1-3 words) that buyers would use to search for this product. Return only valid JSON.
</task>';

		return PromptFormatter::cleanContent( implode( "\n\n", array_filter( $prompt_parts ) ) );
	}

	/**
	 * Builds the system prompt for keyword-optimized meta generation (Phase 2 of two-phase).
	 *
	 * @param string $language      The target language.
	 * @param string $focus_keyword The focus keyword to optimize for.
	 * @param array  $options       Generation options.
	 *
	 * @return string The system prompt for optimized meta generation.
	 */
	public function buildOptimizedMetaSystemPrompt( $language, $focus_keyword, $options = array() ) {
		$tone             = isset( $options['tone'] ) ? $options['tone'] : 'Professional';
		$title_max_length = isset( $options['titleMaxLength'] ) ? (int) $options['titleMaxLength'] : self::TITLE_MAX_LENGTH;
		$desc_max_length  = isset( $options['descMaxLength'] ) ? (int) $options['descMaxLength'] : self::DESC_MAX_LENGTH;
		$generate_title   = isset( $options['generateTitle'] ) ? $options['generateTitle'] : true;
		$generate_desc    = isset( $options['generateDescription'] ) ? $options['generateDescription'] : true;

		$sanitized_focus_keyword = $this->sanitizeFocusKeyword( (string) $focus_keyword );

		$prompt_parts   = array();
		$prompt_parts[] = $this->getIdentitySection();
		$prompt_parts[] = $this->getLanguageStyleSection( $language, $tone );
		$prompt_parts[] = $this->getCoreRulesSection( $title_max_length, $desc_max_length );

		$prompt_parts[] = "# Target Focus Keyword
Your target focus keyword is: \"{$sanitized_focus_keyword}\"

Keyword Integration Rules:
1. The focus keyword MUST appear naturally in the meta title (preferably near the beginning).
2. The focus keyword MUST appear at least once in the meta description.
3. Keyword placement should feel organic - NEVER force or stuff keywords unnaturally.
4. Maintain readability and user appeal - SEO should enhance, not harm, click-through rates.";

		$prompt_parts[] = $this->getQualityGateSection( $title_max_length, $desc_max_length );
		$prompt_parts[] = $this->getOptimizedOutputFormatSection( $generate_title, $generate_desc );

		return PromptFormatter::cleanContent( implode( "\n\n", array_filter( $prompt_parts ) ) );
	}

	/**
	 * Builds the user prompt for keyword-optimized meta generation (Phase 2 of two-phase).
	 *
	 * @param array  $product_data  Product data array.
	 * @param string $focus_keyword The focus keyword to optimize for.
	 * @param array  $options       Generation options.
	 *
	 * @return string The user prompt for optimized meta generation.
	 */
	public function buildOptimizedMetaUserPrompt( $product_data, $focus_keyword, $options = array() ) {
		$sources = isset( $options['sources'] ) && is_array( $options['sources'] )
			? $options['sources']
			: array( 'product_name', 'product_description', 'product_categories' );

		$generate_title = isset( $options['generateTitle'] ) ? $options['generateTitle'] : true;
		$generate_desc  = isset( $options['generateDescription'] ) ? $options['generateDescription'] : true;

		$sanitized_focus_keyword = $this->sanitizeFocusKeyword( (string) $focus_keyword );

		$prompt_parts   = array();
		$prompt_parts[] = $this->getProductDataSection( $product_data, $sources );

		$current_meta = $this->getCurrentMetaSection( $product_data );
		if ( ! empty( $current_meta ) ) {
			$prompt_parts[] = $current_meta;
		}

		$additional_instructions = $this->getAdditionalInstructionsSection( $options, $product_data );
		if ( $additional_instructions ) {
			$prompt_parts[] = $additional_instructions;
		}

		$tasks = array();
		if ( $generate_title ) {
			$tasks[] = 'an SEO-optimized meta title';
		}
		if ( $generate_desc ) {
			$tasks[] = 'a compelling meta description';
		}
		$task_list = implode( ' and ', $tasks );

		$prompt_parts[] = "<task>
Generate {$task_list} for this product, optimized for the focus keyword \"{$sanitized_focus_keyword}\". The keyword must appear naturally in both the title and description. Return only valid JSON.
</task>";

		return PromptFormatter::cleanContent( implode( "\n\n", array_filter( $prompt_parts ) ) );
	}

	/**
	 * Builds the system prompt for keyword-optimized variant generation (Phase 2 of two-phase with variants).
	 *
	 * @param string $language      The target language.
	 * @param string $focus_keyword The focus keyword to optimize for.
	 * @param array  $options       Generation options including 'variantCount'.
	 *
	 * @return string The system prompt for optimized variant generation.
	 */
	public function buildOptimizedVariantSystemPrompt( $language, $focus_keyword, $options = array() ) {
		$tone             = isset( $options['tone'] ) ? $options['tone'] : 'Professional';
		$title_max_length = isset( $options['titleMaxLength'] ) ? (int) $options['titleMaxLength'] : self::TITLE_MAX_LENGTH;
		$desc_max_length  = isset( $options['descMaxLength'] ) ? (int) $options['descMaxLength'] : self::DESC_MAX_LENGTH;
		$variant_count    = isset( $options['variantCount'] ) ? max( 1, min( 5, (int) $options['variantCount'] ) ) : 2;
		$generate_title   = isset( $options['generateTitle'] ) ? $options['generateTitle'] : true;
		$generate_desc    = isset( $options['generateDescription'] ) ? $options['generateDescription'] : true;

		$sanitized_focus_keyword = $this->sanitizeFocusKeyword( (string) $focus_keyword );

		$prompt_parts   = array();
		$prompt_parts[] = $this->getIdentitySection();
		$prompt_parts[] = $this->getLanguageStyleSection( $language, $tone );
		$prompt_parts[] = $this->getCoreRulesSection( $title_max_length, $desc_max_length );

		$prompt_parts[] = "# Target Focus Keyword
Your target focus keyword is: \"{$sanitized_focus_keyword}\"

Keyword Integration Rules:
1. The focus keyword MUST appear naturally in each meta title (vary placement across variants).
2. The focus keyword MUST appear at least once in each meta description.
3. Keyword placement should feel organic - NEVER force or stuff keywords unnaturally.
4. Vary keyword placement across variants to test different SEO approaches.
5. Maintain readability and user appeal in all variants.";

		$prompt_parts[] = $this->getVariantRulesSection( $variant_count );
		$prompt_parts[] = $this->getQualityGateSection( $title_max_length, $desc_max_length );
		$prompt_parts[] = $this->getOptimizedVariantOutputFormatSection( $variant_count, $generate_title, $generate_desc );

		return PromptFormatter::cleanContent( implode( "\n\n", array_filter( $prompt_parts ) ) );
	}

	/**
	 * Builds the user prompt for keyword-optimized variant generation (Phase 2 of two-phase with variants).
	 *
	 * @param array  $product_data  Product data array.
	 * @param string $focus_keyword The focus keyword to optimize for.
	 * @param array  $options       Generation options including 'variantCount'.
	 *
	 * @return string The user prompt for optimized variant generation.
	 */
	public function buildOptimizedVariantUserPrompt( $product_data, $focus_keyword, $options = array() ) {
		$sources = isset( $options['sources'] ) && is_array( $options['sources'] )
			? $options['sources']
			: array( 'product_name', 'product_description', 'product_categories' );

		$variant_count  = isset( $options['variantCount'] ) ? max( 1, min( 5, (int) $options['variantCount'] ) ) : 2;
		$generate_title = isset( $options['generateTitle'] ) ? $options['generateTitle'] : true;
		$generate_desc  = isset( $options['generateDescription'] ) ? $options['generateDescription'] : true;

		$sanitized_focus_keyword = $this->sanitizeFocusKeyword( (string) $focus_keyword );

		$prompt_parts   = array();
		$prompt_parts[] = $this->getProductDataSection( $product_data, $sources );

		$current_meta = $this->getCurrentMetaSection( $product_data );
		if ( ! empty( $current_meta ) ) {
			$prompt_parts[] = $current_meta;
		}

		$additional_instructions = $this->getAdditionalInstructionsSection( $options, $product_data );
		if ( $additional_instructions ) {
			$prompt_parts[] = $additional_instructions;
		}

		$tasks = array();
		if ( $generate_title ) {
			$tasks[] = 'SEO-optimized meta titles';
		}
		if ( $generate_desc ) {
			$tasks[] = 'compelling meta descriptions';
		}
		$task_list = implode( ' and ', $tasks );

		$prompt_parts[] = "<task>
Generate {$variant_count} distinct variants with {$task_list} for this product, all optimized for the focus keyword \"{$sanitized_focus_keyword}\". Each variant must take a different approach while naturally incorporating the keyword. Return only valid JSON.
</task>";

		return PromptFormatter::cleanContent( implode( "\n\n", array_filter( $prompt_parts ) ) );
	}

	private function getOptimizedOutputFormatSection( $generate_title = true, $generate_desc = true ) {
		$fields = array();
		if ( $generate_title ) {
			$fields[] = '"meta_title": "Your SEO title here"';
		}
		if ( $generate_desc ) {
			$fields[] = '"meta_description": "Your SEO description here"';
		}

		if ( empty( $fields ) ) {
			throw new \InvalidArgumentException( 'At least one output field (title or description) must be selected.' );
		}

		$json_example = '{' . implode( ', ', $fields ) . '}';

		return '<output_format>
Return ONLY valid JSON with no additional text or explanation:
' . $json_example . '
</output_format>';
	}

	private function getOptimizedVariantOutputFormatSection( $variant_count, $generate_title = true, $generate_desc = true ) {

		$variants = $this->buildVariantFields( (int) $variant_count, (bool) $generate_title, (bool) $generate_desc, false );

		return '<output_format>
Return ONLY valid JSON with no additional text or explanation:
{
  "variants": [
    ' . implode( ",\n    ", $variants ) . '
  ]
}
</output_format>';
	}

	/**
	 * Sanitizes a focus keyword for safe prompt interpolation.
	 *
	 * Strips control characters, collapses whitespace, removes injection patterns,
	 * and truncates to reasonable length for keyword usage.
	 *
	 * @param string $focus_keyword The raw focus keyword.
	 * @return string Sanitized focus keyword.
	 * @throws \InvalidArgumentException If keyword is empty after sanitization.
	 */
	private function sanitizeFocusKeyword( string $focus_keyword ): string {
		$sanitized = $this->sanitizePromptField( $focus_keyword, 100 );
		if ( $sanitized === '' ) {
			throw new \InvalidArgumentException( 'Focus keyword cannot be empty after sanitization.' );
		}
		return $sanitized;
	}

	/**
	 * Builds the additional instructions section from premium settings.
	 *
	 * @param array $options Generation options containing 'additional_prompt'.
	 * @param array $product_data Product data for variable replacement.
	 * @return string|null XML-tagged additional instructions or null if empty.
	 */
	private function getAdditionalInstructionsSection( array $options, array $product_data = array() ): ?string {
		if ( empty( $options['additional_prompt'] ) ) {
			return null;
		}

		$additional_prompt = PromptFormatter::cleanContent( $options['additional_prompt'] );
		if ( empty( trim( $additional_prompt ) ) ) {
			return null;
		}

		$formatted_prompt = PromptFormatter::formatProductVariables( $additional_prompt, $product_data );

		return "<additional_instructions>\n{$formatted_prompt}\n</additional_instructions>";
	}

	/**
	 * Builds variant fields array for output format sections.
	 *
	 * Extracted helper to reduce duplication between getVariantOutputFormatSection
	 * and getOptimizedVariantOutputFormatSection.
	 *
	 * @param int  $variant_count    Number of variants to generate.
	 * @param bool $generate_title   Whether to include meta title.
	 * @param bool $generate_desc    Whether to include meta description.
	 * @param bool $include_focus_kw Whether to include focus keyword.
	 *
	 * @return array Array of JSON-like variant strings.
	 * @throws \InvalidArgumentException If no fields selected.
	 */
	private function buildVariantFields( int $variant_count, bool $generate_title, bool $generate_desc, bool $include_focus_kw = false ): array {
		$variants = array();
		for ( $i = 1; $i <= $variant_count; $i++ ) {
			$fields = array();
			if ( $generate_title ) {
				$fields[] = '"meta_title": "Variant ' . $i . ' title"';
			}
			if ( $generate_desc ) {
				$fields[] = '"meta_description": "Variant ' . $i . ' description"';
			}
			if ( $include_focus_kw ) {
				$fields[] = '"focus_keyword": "keyword' . $i . '"';
			}

			if ( ! empty( $fields ) ) {
				$variants[] = '{' . implode( ', ', $fields ) . '}';
			}
		}

		if ( empty( $variants ) ) {
			throw new \InvalidArgumentException( 'At least one SEO field (title, description, or focus keyword) must be selected for generation.' );
		}

		return $variants;
	}

	/**
	 * Returns the identity section of the system prompt.
	 *
	 * @return string
	 */
	private function getIdentitySection() {
		return "# Identity
You are an expert SEO specialist who creates search-optimized meta tags for e-commerce products. You understand Google's ranking factors and write meta content that maximizes click-through rates while accurately representing products.";
	}

	/**
	 * Returns the language and style section.
	 *
	 * @param string $language The target language.
	 * @param string $tone     The writing tone.
	 *
	 * @return string
	 */
	private function getLanguageStyleSection( $language, $tone ) {
		$style_guidance = $this->getToneGuidance( $tone );

		return "# Language & Style
- Language: {$language}
- Tone: {$tone}
- {$style_guidance}";
	}

	/**
	 * Returns tone-specific guidance.
	 *
	 * @param string $tone The writing tone.
	 *
	 * @return string
	 */
	private function getToneGuidance( $tone ) {
		$guidance = array(
			'Professional'  => 'Write with authority and clarity. Use industry terminology confidently. No fluff or filler words.',
			'Casual'        => 'Write conversationally and approachably. Use contractions. Keep it friendly but informative.',
			'Persuasive'    => 'Focus on benefits and value propositions. Use action words. Create urgency without being pushy.',
			'Informative'   => 'Lead with key facts and specifications. Be precise and helpful. Prioritize clarity over style.',
			'Luxury'        => 'Understated elegance. Focus on craftsmanship and quality. No exclamation marks. Let quality speak.',
			'SEO-Focused'   => 'Prioritize keyword placement naturally. Balance search optimization with readability.',
		);

		$tone_lower = strtolower( $tone );
		foreach ( $guidance as $key => $value ) {
			if ( strtolower( $key ) === $tone_lower ) {
				return $value;
			}
		}

		return $guidance['Professional'];
	}

	/**
	 * Returns the core rules section.
	 *
	 * @param int $title_max The maximum title length.
	 * @param int $desc_max  The maximum description length.
	 *
	 * @return string
	 */
	private function getCoreRulesSection( $title_max, $desc_max ) {
		return "# Core Rules
1. Meta Title: Maximum {$title_max} characters. Start with the product name. Include key differentiator. Brand at end if space allows.
2. Meta Description: Maximum {$desc_max} characters. Highlight unique selling point. Include a call-to-action. Make it compelling.
3. NEVER use markdown formatting in output - plain text only.
4. NEVER use emojis or special characters.
5. Be SPECIFIC - use actual product details from the data provided.
6. Do NOT invent features or specifications not mentioned in the product data.
7. NEVER include literal prices, price ranges, currency amounts, or SKU/model numbers in the meta title or description. Prices change frequently and SKU codes are not user-friendly. Use them only to understand the product's market positioning if provided.";
	}

	/**
	 * Returns the keyword optimization section for focus keyword-optimized content.
	 *
	 * This section instructs the AI to naturally incorporate the focus keyword
	 * into both the meta title and description when the premium feature is enabled.
	 *
	 * @return string
	 */
	private function getKeywordOptimizationSection() {
		return "# Keyword Optimization Rules
When generating focus keyword-optimized content:
1. The focus keyword MUST appear naturally in the meta title (preferably near the beginning).
2. The focus keyword MUST appear at least once in the meta description.
3. Keyword placement should feel organic - NEVER force or stuff keywords unnaturally.
4. If the product name contains the focus keyword concept, leverage that in your title.
5. Vary keyword placement across variants to test different SEO approaches.
6. Maintain readability and user appeal - SEO should enhance, not harm, click-through rates.";
	}

	/**
	 * Returns the quality gate section.
	 *
	 * @param int $title_max The maximum title length.
	 * @param int $desc_max  The maximum description length.
	 *
	 * @return string
	 */
	private function getQualityGateSection( $title_max, $desc_max ) {
		return "# Quality Gate
Before finalizing, verify:
- Title is under {$title_max} characters
- Description is under {$desc_max} characters
- Title starts with the product name
- Description includes a call-to-action (Shop now, Discover, Get yours, etc.)
- No markdown, no emojis, no special formatting
- Content accurately reflects the product";
	}

	/**
	 * Returns the output format section.
	 *
	 * @param bool $include_focus_kw Whether to include focus keyword in output.
	 * @param bool $generate_title   Whether to generate meta title.
	 * @param bool $generate_desc    Whether to generate meta description.
	 *
	 * @return string
	 */
	private function getOutputFormatSection( $include_focus_kw, $generate_title = true, $generate_desc = true ) {
		$fields = array();
		
		if ( $generate_title ) {
			$fields[] = '"meta_title": "Your SEO title here"';
		}
		if ( $generate_desc ) {
			$fields[] = '"meta_description": "Your SEO description here"';
		}
		if ( $include_focus_kw ) {
			$fields[] = '"focus_keyword": "primary keyword"';
		}
		

		if ( empty( $fields ) ) {
			throw new \InvalidArgumentException( 'At least one output field (title, description, or focus keyword) must be selected.' );
		}
		
		$json_example = '{' . implode( ', ', $fields ) . '}';
		
		return '<output_format>
Return ONLY valid JSON with no additional text or explanation:
' . $json_example . '
</output_format>';
	}

	/**
	 * Returns the product data section with XML tags.
	 *
	 * Product data is sanitized to prevent prompt injection:
	 * - Control characters and newlines are stripped
	 * - AI-instruction-like patterns are removed
	 * - Fields are truncated to safe lengths
	 *
	 * @param array $product_data The product data.
	 * @param array $sources      Selected data sources to include.
	 *
	 * @return string
	 */
	private function getProductDataSection( $product_data, $sources = array() ) {
		$name        = isset( $product_data['name'] ) ? $this->sanitizePromptField( $product_data['name'], 200 ) : 'Unknown Product';

		$raw_category = $product_data['categories'] ?? $product_data['category'] ?? '';
		$category    = ! empty( $raw_category ) ? $this->sanitizePromptField( $raw_category, 200 ) : '';
		$price       = isset( $product_data['price'] ) ? $this->sanitizePromptField( $product_data['price'], 50 ) : '';
		$short_desc  = isset( $product_data['short_description'] ) ? $this->sanitizePromptField( $product_data['short_description'], 300 ) : '';
		$description = isset( $product_data['description'] ) ? $this->sanitizePromptField( $product_data['description'], 500 ) : '';
		$attributes  = isset( $product_data['attributes'] ) ? $this->sanitizePromptField( $product_data['attributes'], 300 ) : '';
		$sku         = isset( $product_data['sku'] ) ? $this->sanitizePromptField( $product_data['sku'], 50 ) : '';
		$brand       = isset( $product_data['brand'] ) ? $this->sanitizePromptField( $product_data['brand'], 100 ) : '';
		$tags        = isset( $product_data['tags'] ) ? $this->sanitizePromptField( $product_data['tags'], 200 ) : '';

		$data_lines = array();

		if ( in_array( 'product_name', $sources, true ) && ! empty( $name ) ) {
			$data_lines[] = "Name: {$name}";
		}

		if ( in_array( 'product_brand', $sources, true ) && ! empty( $brand ) ) {
			$data_lines[] = "Brand: {$brand}";
		}
		if ( in_array( 'product_categories', $sources, true ) && ! empty( $category ) ) {
			$data_lines[] = "Category: {$category}";
		}
		if ( in_array( 'product_price', $sources, true ) && ! empty( $price ) ) {
			$data_lines[] = "Price: {$price}";
		}
		if ( in_array( 'product_sku', $sources, true ) && ! empty( $sku ) ) {
			$data_lines[] = "SKU: {$sku}";
		}
		if ( in_array( 'short_description', $sources, true ) && ! empty( $short_desc ) ) {
			$data_lines[] = "Short Description: {$short_desc}";
		}
		if ( in_array( 'product_description', $sources, true ) && ! empty( $description ) ) {
			$data_lines[] = "Description: {$description}";
		}
		if ( in_array( 'product_attributes', $sources, true ) && ! empty( $attributes ) ) {
			$data_lines[] = "Attributes: {$attributes}";
		}
		if ( in_array( 'product_tags', $sources, true ) && ! empty( $tags ) ) {
			$data_lines[] = "Tags: {$tags}";
		}

		if ( empty( $data_lines ) && ! empty( $name ) ) {
			$data_lines[] = "Name: {$name}";
		}

		return "<product_data>\n" . implode( "\n", $data_lines ) . "\n</product_data>";
	}

	/**
	 * Sanitizes a field value for safe prompt injection.
	 *
	 * @param string $value     The raw field value.
	 * @param int    $max_length Maximum allowed length.
	 *
	 * @return string Sanitized value.
	 */
	private function sanitizePromptField( $value, $max_length = 500 ) {

		if ( is_array( $value ) ) {
			$value = implode( ', ', array_filter( array_map( 'strval', $value ) ) );
		}

		if ( ! is_string( $value ) ) {
			$value = (string) $value;
		}

		$value = wp_strip_all_tags( $value );

		if ( class_exists( '\\Normalizer' ) ) {
			$normalized = \Normalizer::normalize( $value, \Normalizer::FORM_KC );
			if ( is_string( $normalized ) ) {
				$value = $normalized;
			}
		}

		$homoglyph_map = array(
			'А' => 'A', 'В' => 'B', 'Е' => 'E', 'К' => 'K', 'М' => 'M', 'Н' => 'H', 'О' => 'O', 'Р' => 'P', 'С' => 'C', 'Т' => 'T', 'Х' => 'X',
			'а' => 'a', 'е' => 'e', 'о' => 'o', 'р' => 'p', 'с' => 'c', 'х' => 'x', 'у' => 'y', 'і' => 'i', 'І' => 'I', 'ј' => 'j', 'Ј' => 'J',
			'Α' => 'A', 'Β' => 'B', 'Ε' => 'E', 'Ζ' => 'Z', 'Η' => 'H', 'Ι' => 'I', 'Κ' => 'K', 'Μ' => 'M', 'Ν' => 'N', 'Ο' => 'O',
			'Ρ' => 'P', 'Τ' => 'T', 'Υ' => 'Y', 'Χ' => 'X', 'α' => 'a', 'β' => 'b', 'γ' => 'y', 'ι' => 'i', 'κ' => 'k', 'ο' => 'o', 'ρ' => 'p',
			'τ' => 't', 'υ' => 'y', 'χ' => 'x',
		);
		$value = strtr( $value, $homoglyph_map );

		$result = preg_replace( '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $value );
		$value  = is_string( $result ) ? $result : $value;

		$result = preg_replace( '/\s+/', ' ', $value );
		$value  = is_string( $result ) ? $result : $value;

		foreach ( self::INJECTION_PATTERNS as $pattern ) {
			$result = preg_replace( $pattern, '', $value );
			$value  = is_string( $result ) ? $result : $value;
		}

		if ( function_exists( 'mb_strlen' ) ) {
			$length = mb_strlen( $value, 'UTF-8' );
		} else {
			$length = strlen( $value );
		}

		if ( $length > $max_length ) {
			if ( $max_length <= 3 ) {
				if ( function_exists( 'mb_substr' ) ) {
					$value = mb_substr( $value, 0, $max_length );
				} else {
					$value = substr( $value, 0, $max_length );
				}
			} else {
				if ( function_exists( 'mb_substr' ) ) {
					$value = mb_substr( $value, 0, $max_length - 3 ) . '...';
				} else {
					$value = substr( $value, 0, $max_length - 3 ) . '...';
				}
			}
		}

		return trim( $value );
	}

	/**
	 * Returns current meta section if available.
	 *
	 * @param array $product_data The product data.
	 *
	 * @return string
	 */
	private function getCurrentMetaSection( $product_data ) {
		$current_title = isset( $product_data['current_seo_title'] )
			? $this->sanitizePromptField( $product_data['current_seo_title'], 200 )
			: '';
		$current_desc  = isset( $product_data['current_seo_description'] )
			? $this->sanitizePromptField( $product_data['current_seo_description'], 300 )
			: '';

		if ( empty( $current_title ) && empty( $current_desc ) ) {
			return '';
		}

		$lines = array();
		if ( ! empty( $current_title ) ) {
			$lines[] = "Current Meta Title: {$current_title}";
		}
		if ( ! empty( $current_desc ) ) {
			$lines[] = "Current Meta Description: {$current_desc}";
		}

		return "<current_meta>\n" . implode( "\n", $lines ) . "\n</current_meta>";
	}

	/**
	 * Returns the task section.
	 *
	 * @param array $options Generation options.
	 *
	 * @return string
	 * @throws \InvalidArgumentException If no tasks are selected.
	 */
	private function getTaskSection( $options ) {
		$tasks = array();

		$generate_title = isset( $options['generateTitle'] ) ? $options['generateTitle'] : true;
		$generate_desc  = isset( $options['generateDescription'] ) ? $options['generateDescription'] : true;
		$generate_kw    = ! empty( $options['generateFocusKeyword'] );

		if ( $generate_title ) {
			$tasks[] = 'an SEO-optimized meta title';
		}
		if ( $generate_desc ) {
			$tasks[] = 'a compelling meta description';
		}
		if ( $generate_kw ) {
			$tasks[] = 'a focus keyword (1-3 words)';
		}

		if ( empty( $tasks ) ) {
			throw new \InvalidArgumentException( 'At least one SEO field (title, description, or focus keyword) must be selected for generation.' );
		}

		$task_list = implode( ', ', $tasks );

		return "<task>
Generate {$task_list} for this product. Use the product data provided. Follow all rules and quality gates. Return only valid JSON.
</task>";
	}

	/**
	 * Returns variant-specific rules section.
	 *
	 * @param int $variant_count Number of variants to generate.
	 *
	 * @return string
	 */
	private function getVariantRulesSection( $variant_count ) {
		return "# Variant Generation Rules
1. Generate exactly {$variant_count} distinct variants.
2. Each variant must take a meaningfully different approach or angle:
   - Variant 1: Focus on product benefits and value proposition
   - Variant 2: Focus on features and specifications
   - Variant 3 (if applicable): Focus on use cases and applications
   - Variant 4 (if applicable): Focus on quality and craftsmanship
   - Variant 5 (if applicable): Focus on urgency and availability
3. Ensure each variant is unique in tone, emphasis, and keyword placement.
4. All variants must comply with character limits and quality gates.";
	}

	/**
	 * Returns the output format section for variant generation.
	 *
	 * @param bool $include_focus_kw Whether to include focus keyword in output.
	 * @param int  $variant_count    Number of variants to generate.
	 * @param bool $generate_title   Whether to generate meta title.
	 * @param bool $generate_desc    Whether to generate meta description.
	 *
	 * @return string
	 */
	private function getVariantOutputFormatSection( $include_focus_kw, $variant_count, $generate_title = true, $generate_desc = true ) {

		$variants = $this->buildVariantFields( (int) $variant_count, (bool) $generate_title, (bool) $generate_desc, (bool) $include_focus_kw );

		return '<output_format>
Return ONLY valid JSON with no additional text or explanation:
{
  "variants": [
    ' . implode( ",\n    ", $variants ) . '
  ]
}
</output_format>';
	}

	/**
	 * Returns the task section for variant generation.
	 *
	 * @param array $options       Generation options.
	 * @param int   $variant_count Number of variants to generate.
	 *
	 * @return string
	 * @throws \InvalidArgumentException If no tasks are selected.
	 */
	private function getVariantTaskSection( $options, $variant_count ) {
		$tasks = array();

		$generate_title = isset( $options['generateTitle'] ) ? $options['generateTitle'] : true;
		$generate_desc  = isset( $options['generateDescription'] ) ? $options['generateDescription'] : true;
		$generate_kw    = ! empty( $options['generateFocusKeyword'] );

		if ( $generate_title ) {
			$tasks[] = 'SEO-optimized meta titles';
		}
		if ( $generate_desc ) {
			$tasks[] = 'compelling meta descriptions';
		}
		if ( $generate_kw ) {
			$tasks[] = 'focus keywords (1-3 words each)';
		}

		if ( empty( $tasks ) ) {
			throw new \InvalidArgumentException( 'At least one SEO field (title, description, or focus keyword) must be selected for variant generation.' );
		}

		$task_list = implode( ', ', $tasks );

		return "<task>
Generate {$variant_count} distinct variants with {$task_list} for this product. Each variant must take a different approach. Use the product data provided. Follow all rules and quality gates. Return only valid JSON.
</task>";
	}
}
