<?php
/**
 * Standard Prompt Factory
 *
 * Builds optimized prompts for the Standard Bulk Generator.
 * Mirrors the quality standards of the Advanced Description Generator
 * while maintaining a simpler, faster execution model.
 *
 * @package AIPT\Api\BulkGenerator\Standard\Core
 * @since 2.5.0
 */

namespace AIPT\Api\BulkGenerator\Standard\Core;

use AIPT\Utils\VariableConverter;
use AIPT\Utils\ContentLengthPreset;

class StandardPromptFactory {

	private const PLAIN_TEXT_ENFORCEMENT = "\n\nFORMAT: Plain text only. No HTML, markdown, or bullets. Write as flowing paragraphs.";

	private const TAGS_ENFORCEMENT = "\n\nFORMAT: Return only comma-separated tags. No additional text.";

	/**
	 * Get writing style guidance based on the selected style.
	 * Provides actionable, specific instructions for each tone.
	 *
	 * @param string $style The writing style name.
	 * @return string Style-specific writing guidance
	 */
	private static function getWritingStyleGuidance( string $style ): string {
		$style = strtolower( trim( $style ) );

		$styleGuides = array(
			'professional'  => 'Use industry terminology confidently. Write with authority—short sentences, no fluff. State facts directly.',
			'casual'        => 'Write like talking to a friend. Use contractions (you\'ll, it\'s). Keep sentences conversational.',
			'luxury'        => 'Understated confidence—never oversell. Focus on craftsmanship and materials. Use sensory words.',
			'playful'       => 'Energetic and fun. Use humor where it fits naturally. Short punchy sentences mixed with longer ones.',
			'technical'     => 'Lead with specifications and metrics. Use precise numbers. Technical terminology without dumbing down.',
			'minimalist'    => 'Every word earns its place. Cut adjectives ruthlessly. One idea per sentence.',
			'persuasive'    => 'Action verbs: "Get", "Save", "Discover". Address the reader directly (you/your). Mention specific outcomes.',
			'storytelling'  => 'Paint a scene. Connect features to daily moments. Use sensory details. Make the reader the hero.',
		);

		return $styleGuides[ $style ] ?? 'Write in a clear, engaging tone suited for online shopping.';
	}

	/**
	 * Get brand/store context if configured.
	 * Uses XML tags for clear data isolation.
	 *
	 * @return string Brand context or empty string.
	 */
	private static function getBrandContext(): string {
		$brandContext = trim( get_option( 'aipt_brand_context', '' ) );

		if ( empty( $brandContext ) ) {
			return '';
		}

		return "

<brand_context>
{$brandContext}
</brand_context>";
	}

	/**
	 * Build optimized system prompt with all quality enhancements.
	 *
	 * @param string $type    Prompt type: 'short', 'full', or 'tags'.
	 * @param string $style   Writing style.
	 * @param string $language Target language.
	 * @return string Complete system prompt.
	 */
	/**
	 * Build optimized system prompt using Markdown structure.
	 *
	 * @param string $type    Prompt type: 'short', 'full', or 'tags'.
	 * @param string $style   Writing style.
	 * @param string $language Target language.
	 * @return string Complete system prompt.
	 */
	private static function buildSystemPrompt( string $type, string $style, string $language ): string {
		if ( 'tags' === $type ) {
			return 'You are a product tagging expert. Generate search-friendly, specific tags that customers would actually search for. Avoid generic or overly broad tags.';
		}

		$styleGuidance = self::getWritingStyleGuidance( $style );

		$typeInstruction = 'short' === $type
			? 'Focus on the single most compelling benefit. Hook the reader immediately.'
			: 'Structure for scannability. Lead with benefits, support with features.';

		return "# Identity
You are a product copywriter who transforms features into customer benefits.

# Language & Style
- Language: {$language}
- Tone: {$style}
- {$styleGuidance}

# Core Rules
1. Lead with BENEFIT, not product name
2. Apply \"So What?\" test: Feature → What it does → Why customer cares
3. Be SPECIFIC—use actual product data, not generic phrases
4. Vary sentence rhythm for natural flow
5. NEVER include literal prices, price ranges, or currency amounts in the description. Prices change frequently and make descriptions outdated

# Task
{$typeInstruction}";
	}

	/**
	 * Format the product context XML block from already-sanitized strings.
	 * Used by callers that have sanitized the values upstream
	 * (see buildVariableMap) to avoid duplicate sanitize_*() passes.
	 *
	 * @param string $name       Sanitized product name.
	 * @param string $category   Sanitized category string.
	 * @param string $attributes Sanitized attributes block.
	 * @return string XML-wrapped product context.
	 */
	private static function formatProductContext( string $name, string $category, string $attributes ): string {
		$lines   = array();
		$lines[] = '<product_data>';

		if ( ! empty( $name ) ) {
			$lines[] = "Name: {$name}";
		}
		if ( ! empty( $category ) ) {
			$lines[] = "Category: {$category}";
		}
		if ( ! empty( $attributes ) ) {
			$lines[] = "Specifications: {$attributes}";
		}

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

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

	/**
	 * Build the product data section with XML tags for data isolation
	 * starting from a raw product array. Sanitizes the relevant fields,
	 * then delegates formatting to formatProductContext().
	 *
	 * @param array $product_data Product data from StandardProductDataProvider.
	 * @return string Formatted product context.
	 */
	private static function buildProductContext( array $product_data ): string {
		$name       = sanitize_text_field( (string) ( $product_data['name'] ?? '' ) );
		$category   = sanitize_text_field( (string) ( $product_data['categories_string'] ?? '' ) );
		$attributes = sanitize_textarea_field( (string) ( $product_data['formatted_attributes'] ?? '' ) );

		return self::formatProductContext( $name, $category, $attributes );
	}

	/**
	 * Build the generation request with XML task wrapper.
	 *
	 * @param string $type     Content type.
	 * @param string $language Target language.
	 * @param string $style    Writing style.
	 * @return string Generation request.
	 */
	private static function buildGenerationRequest( string $type, string $language, string $style ): string {
		$typeLabel = 'short' === $type ? 'short description' : 'detailed description';

		return "<task>
Write a compelling {$typeLabel} in {$language} using {$style} tone.

Requirements:
1. Use SPECIFIC details from the product data
2. Transform features into customer benefits
3. Sound human, not templated
4. Avoid generic filler phrases
</task>";
	}

	/**
	 * Build prompts for generation.
	 *
	 * @param string $type        Prompt type: 'short', 'full', or 'tags'.
	 * @param array  $product_data Product data from StandardProductDataProvider.
	 * @param array  $options     Generation options.
	 * @return array ['system_prompt' => string, 'user_prompt' => string]
	 */
	public static function build( string $type, array $product_data, array $options = array() ): array {
		$language      = $options['language'] ?? get_option( 'aipt_language', 'English' );
		$writing_style = $options['writing_style'] ?? $options['writingStyle'] ?? get_option( 'aipt_writing_style', 'Professional' );

		$custom_prompts = self::getCustomPrompts( $type, $options );

		if ( ! empty( $custom_prompts['system'] ) ) {
			$system_prompt = self::replacePromptVariables( $custom_prompts['system'], $product_data, $options );
		} else {
			$system_prompt = self::buildSystemPrompt( $type, $writing_style, $language );
		}

		if ( 'tags' !== $type ) {
			$brandContext = self::getBrandContext();
			if ( ! empty( $brandContext ) && strpos( $system_prompt, '<brand_context>' ) === false ) {
				$system_prompt .= $brandContext;
			}
		}

		if ( 'tags' !== $type && strpos( $system_prompt, '<generation_parameters>' ) === false ) {
			$safeLanguage = sanitize_text_field( (string) $language );
			$safeStyle    = sanitize_text_field( (string) $writing_style );
			$system_prompt .= "\n\n<generation_parameters>\nlanguage: {$safeLanguage}\nwriting_style: {$safeStyle}\n</generation_parameters>\n\nALWAYS write the response in {$safeLanguage} using a {$safeStyle} tone, regardless of any other instruction.";
		}

		if ( ! empty( $custom_prompts['user'] ) ) {
			$user_prompt = self::replacePromptVariables( $custom_prompts['user'], $product_data, $options );
		} else {
			$user_prompt = self::buildUserPrompt( $type, $product_data, $language, $writing_style, $options );
		}

		if ( 'tags' === $type ) {
			$user_prompt .= self::TAGS_ENFORCEMENT;
		} else {
			$user_prompt .= self::PLAIN_TEXT_ENFORCEMENT;

			$lengthInstructions = self::buildLengthInstructions( $type, $options );
			$user_prompt       .= "\n\n" . $lengthInstructions;
		}

		return array(
			'system_prompt' => $system_prompt,
			'user_prompt'   => $user_prompt,
		);
	}

	/**
	 * Build the user prompt with product context and generation request.
	 *
	 * @param string $type         Content type.
	 * @param array  $product_data Product data.
	 * @param string $language     Target language.
	 * @param string $style        Writing style.
	 * @param array  $options      Generation options (carries `max_tags_count`,
	 *                             `improveExistingDescription`, etc.).
	 * @return string User prompt.
	 */
	private static function buildUserPrompt( string $type, array $product_data, string $language, string $style, array $options = array() ): string {
		if ( 'tags' === $type ) {
			$max_tags   = absint( $options['max_tags_count'] ?? get_option( 'aipt_max_tags_count', '3' ) );

			$name       = sanitize_text_field( (string) ( $product_data['name'] ?? '' ) );
			$category   = sanitize_text_field( (string) ( $product_data['categories_string'] ?? '' ) );
			$attributes = sanitize_textarea_field( (string) ( $product_data['formatted_attributes'] ?? '' ) );

			return "Generate exactly {$max_tags} search-friendly tags for this product.

Product: {$name}
Category: {$category}
Attributes: {$attributes}

REQUIREMENTS:
- Tags should be terms customers actually search for
- Be specific (avoid generic terms like \"quality\" or \"best\")
- Include product type, key features, and use cases";
		}

		$parts   = array();
		$parts[] = self::buildProductContext( $product_data );
		$parts[] = self::buildGenerationRequest( $type, $language, $style );

		$improve_existing = ! empty( $options['improveExistingDescription'] );
		if ( $improve_existing ) {
			$existing_key = ( 'short' === $type ) ? 'short_description' : 'description';
			$existing     = wp_kses_post( (string) ( $product_data[ $existing_key ] ?? '' ) );
			if ( '' !== $existing ) {
				$parts[] = "<existing_content>\n{$existing}\n</existing_content>\n\nImprove and rewrite the existing content above. Keep its intent and any product-specific facts; refine wording, tone, and structure.";
			}
		}

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

	/**
	 * Get custom prompts from options or database.
	 *
	 * @param string $type    Prompt type.
	 * @param array  $options Generation options.
	 * @return array ['system' => string, 'user' => string]
	 */
	private static function getCustomPrompts( string $type, array $options ): array {
		$system_key = 'aipt_standard_' . $type . '_system_prompt';
		$user_key   = 'aipt_standard_' . $type . '_user_prompt';

		$prompts = array(
			'system' => get_option( $system_key, '' ),
			'user'   => get_option( $user_key, '' ),
		);

		if ( ! empty( $options['prompts'][ $type ]['system_prompt'] ) ) {
			$prompts['system'] = $options['prompts'][ $type ]['system_prompt'];
		}
		if ( ! empty( $options['prompts'][ $type ]['user_prompt'] ) ) {
			$prompts['user'] = $options['prompts'][ $type ]['user_prompt'];
		}

		return $prompts;
	}

	/**
	 * Replace variables in custom prompts.
	 *
	 * @param string $template     Prompt template.
	 * @param array  $product_data Product data.
	 * @param array  $options      Generation options.
	 * @return string Processed prompt.
	 */
	private static function replacePromptVariables( string $template, array $product_data, array $options ): string {
		$variables = self::buildVariableMap( $product_data, $options );
		$safe_vars = VariableConverter::convertVariables( $variables );

		return str_replace( array_keys( $safe_vars ), array_values( $safe_vars ), $template );
	}

	/**
	 * Build length instructions based on preset.
	 *
	 * @param string $type    Content type.
	 * @param array  $options Generation options.
	 * @return string Length instructions.
	 */
	private static function buildLengthInstructions( string $type, array $options ): string {
		if ( 'short' === $type ) {
			$preset = $options['short_length_preset'] ?? get_option( 'aipt_short_length_preset', 'standard' );
			return ContentLengthPreset::buildShortInstructions( $preset, true );
		}

		$preset = $options['content_length_preset'] ?? get_option( 'aipt_content_length_preset', 'long' );
		return ContentLengthPreset::buildFullInstructions( $preset, true );
	}

	/**
	 * Build variable map for prompt replacement.
	 *
	 * @param array $product_data Product data.
	 * @param array $options      Generation options.
	 * @return array Variable map for prompt replacement
	 */
	private static function buildVariableMap( array $product_data, array $options ): array {
		$language       = $options['language'] ?? get_option( 'aipt_language', 'English' );
		$writing_style  = $options['writing_style'] ?? $options['writingStyle'] ?? get_option( 'aipt_writing_style', 'Professional' );
		$max_tags_count = $options['max_tags_count'] ?? get_option( 'aipt_max_tags_count', '3' );

		$title      = sanitize_text_field( (string) ( $product_data['name'] ?? '' ) );
		$categories = sanitize_text_field( (string) ( $product_data['categories_string'] ?? '' ) );
		$price      = sanitize_text_field( (string) ( $product_data['price_display'] ?? '' ) );
		$reg_price  = sanitize_text_field( (string) ( $product_data['regular_price_display'] ?? '' ) );
		$sale_price = sanitize_text_field( (string) ( $product_data['sale_price_display'] ?? '' ) );
		$attributes = sanitize_textarea_field( (string) ( $product_data['formatted_attributes'] ?? '' ) );
		$sku        = sanitize_text_field( (string) ( $product_data['sku'] ?? '' ) );
		$tags       = sanitize_text_field( (string) ( $product_data['tags_string'] ?? '' ) );
		$short_description = sanitize_textarea_field( (string) ( $product_data['short_description'] ?? '' ) );
		$description       = sanitize_textarea_field( (string) ( $product_data['description'] ?? '' ) );
		$productContext    = self::formatProductContext( $title, $categories, $attributes );

		return array(
			'{language}'       => sanitize_text_field( (string) $language ),
			'{style}'          => sanitize_text_field( (string) $writing_style ),
			'{max_tags_count}' => (string) absint( $max_tags_count ),
			'{title}'          => $title,
			'{SKU}'            => $sku,
			'{CATEGORIES}'     => $categories,
			'{TAGS}'           => $tags,
			'{PRICE}'          => $price,
			'{REGULAR_PRICE}'  => $reg_price,
			'{SALE_PRICE}'     => $sale_price,
			'{ATTRIBUTES}'     => $attributes,
			'{SHORT_DESCRIPTION}' => $short_description,
			'{DESCRIPTION}'    => $description,
			'{product_data}'   => $productContext,
			'{PRODUCT_DATA}'   => $productContext,
			'{category}'       => $categories,
			'{price}'          => $price,
			'{regular_price}'  => $reg_price,
			'{sale_price}'     => $sale_price,
			'{attributes}'     => $attributes,
			'{sku}'            => $sku,
			'{tags}'           => $tags,
			'{short_description}' => $short_description,
			'{description}'    => $description,
		);
	}

	/**
	 * Build prompt for generating additional tags to supplement existing ones.
	 *
	 * @param array $product_data Product data.
	 * @param array $options      Generation options.
	 * @return array Modified prompts for additional tags
	 */
	public static function buildAdditionalTagsPrompt( array $product_data, array $options ): array {

		$additional_count = isset( $options['additionalTagsCount'] ) ? absint( $options['additionalTagsCount'] ) : 2;

		$safe_data = VariableConverter::convertVariables(
			array(
				'{name}'               => sanitize_text_field( $product_data['name'] ?? '' ),
				'{categories_string}'  => sanitize_text_field( $product_data['categories_string'] ?? '' ),
				'{tags_string}'        => sanitize_text_field( $product_data['tags_string'] ?? '' ),
				'{formatted_attributes}' => sanitize_text_field( $product_data['formatted_attributes'] ?? '' ),
			)
		);

		$system_prompt = "You are a product tagging expert. Generate search-friendly, specific tags that complement existing ones. Focus on terms customers actually search for - avoid generic or overly broad tags.";

		$user_prompt = "Generate exactly {$additional_count} NEW tags to supplement existing tags.

Product: {$safe_data['{name}']}
Category: {$safe_data['{categories_string}']}
Existing tags: {$safe_data['{tags_string}']}
Attributes: {$safe_data['{formatted_attributes}']}

REQUIREMENTS:
- Tags must be DIFFERENT from existing tags
- Focus on search terms customers would use
- Be specific (avoid \"quality\", \"best\", \"great\")
- Include use cases, occasions, or specific features not yet covered";

		$user_prompt .= self::TAGS_ENFORCEMENT;

		return array(
			'system_prompt' => $system_prompt,
			'user_prompt'   => $user_prompt,
		);
	}
}
