<?php
/**
 * Unified Content Generator Service
 *
 * Generates multiple content types (description, short description, tags, title)
 * in a single AI request for better content consistency and quality.
 *
 * @package AIPT\Api\Services
 * @since 2.6.0
 */

namespace AIPT\Api\Services;

use AIPT\Core\Activator;
use AIPT\Core\ErrorHandler;
use AIPT\Utils\VariableConverter;
use AIPT\Utils\PromptFormatter;

/**
 * Unified Content Generator Implementation
 *
 * Generates multiple content types in a single AI call for:
 * - Better content consistency (short desc aligns with full desc)
 * - Reduced API costs (one call instead of multiple)
 * - Improved quality (AI has full context)
 *
 * @internal Used by RestEndpoints
 */
class UnifiedContentGenerator {

	/**
	 * AI Client Factory
	 *
	 * @var AIClientFactoryInterface
	 */
	private $ai_client_factory;

	/**
	 * Style descriptions for writing styles
	 *
	 * @var array
	 */
	private $style_descriptions;

	/**
	 * Available content types
	 */
	const TYPE_DESCRIPTION = 'description';
	const TYPE_SHORT_DESCRIPTION = 'short_description';
	const TYPE_TAGS = 'tags';
	const TYPE_TITLE = 'title';

	/**
	 * All valid content types
	 *
	 * @var array
	 */
	private static $valid_types = [
		self::TYPE_DESCRIPTION,
		self::TYPE_SHORT_DESCRIPTION,
		self::TYPE_TAGS,
		self::TYPE_TITLE,
	];

	/**
	 * Constructor
	 *
	 * @param AIClientFactoryInterface $ai_client_factory AI client factory
	 * @param array $style_descriptions Style descriptions mapping
	 */
	public function __construct( AIClientFactoryInterface $ai_client_factory, array $style_descriptions = [] ) {
		$this->ai_client_factory  = $ai_client_factory;
		$this->style_descriptions = $style_descriptions ?: $this->getDefaultStyleDescriptions();
	}

	/**
	 * Get default style descriptions
	 *
	 * @return array
	 */
	private function getDefaultStyleDescriptions(): array {
		return [
			'Professional' => 'Use clear, concise, and formal language. Focus on features, benefits, and technical details.',
			'Encouraging' => 'Use positive, motivational language that inspires confidence and action.',
			'Exaggerated' => 'Use dramatic and hyperbolic language to create excitement and emphasis.',
			'Friendly' => 'Use warm, conversational language that builds rapport and trust.',
			'Storytelling' => 'Create a narrative that engages readers and connects emotionally.',
			'Minimalist' => 'Use simple, straightforward language focusing on essential details.',
			'Luxurious and Elegant' => 'Use sophisticated, refined language that conveys premium quality and exclusivity.',
			'Adventurous' => 'Use dynamic, exciting language that creates a sense of exploration and discovery.',
			'Educational' => 'Use informative, detailed language that explains and educates.',
			'Humorous' => 'Use light-hearted, playful language with appropriate humor and wit.',
		];
	}

	/**
	 * Generate multiple content types in a single AI request
	 *
	 * @param int $product_id Product ID
	 * @param array $content_types Array of content types to generate
	 * @param array $options Additional options (improveExisting, keepExisting, etc.)
	 * @return array|\WP_Error Generated content array or error
	 */
	public function generate( int $product_id, array $content_types, array $options = [] ) {
		try {
			$content_types = $this->validateContentTypes( $content_types );
			if ( empty( $content_types ) ) {
				return new \WP_Error( 'invalid_types', 'No valid content types specified', [ 'status' => 400 ] );
			}

			$product = \wc_get_product( $product_id );
			if ( ! $product ) {
				return new \WP_Error( 'invalid_product', 'Invalid product ID', [ 'status' => 404 ] );
			}

			$api_provider  = get_option( 'aipt_api_provider', 'openai' );
			$model         = $this->ai_client_factory->getDefaultModel( $api_provider );
			$model         = get_option( 'aipt_model', $model );
			$model         = $this->ai_client_factory->normalizeModel( $api_provider, $model );

			$language      = get_option( 'aipt_language', Activator::get_default_value( 'language' ) );
			$writing_style = get_option( 'aipt_writing_style', Activator::get_default_value( 'writing_style' ) );

			$style_description = $this->style_descriptions[ $writing_style ] ?? $this->style_descriptions['Professional'];

			$product_info = $this->getProductInfo( $product );

			$prompts = $this->buildUnifiedPrompt( $content_types, $product_info, $language, $style_description, $options );

			$client     = $this->ai_client_factory->create();
			$max_length = $this->calculateMaxLength( $content_types );

			$response = $client->generate_description( 
				$prompts['system'], 
				$prompts['user'], 
				$model, 
				$max_length 
			);

			$parsed = $this->parseResponse( $response, $content_types );
			$result = $this->postProcessContent( $parsed, $content_types, $product, $options );

			return [
				'success'         => true,
				'content'         => $result,
				'types_generated' => array_keys( $result ),
			];

		} catch ( \Exception $e ) {

			$message = $e->getMessage();
			$status  = ErrorHandler::extract_http_status_from_message( $message, 500 );
			return new \WP_Error( 'generation_failed', $message, [ 'status' => $status ] );
		}
	}

	/**
	 * Validate content types
	 *
	 * @param array $types Content types to validate
	 * @return array Valid content types
	 */
	private function validateContentTypes( array $types ): array {
		return array_values( array_intersect( $types, self::$valid_types ) );
	}

	/**
	 * Build unified prompt for multiple content types
	 *
	 * @param array $content_types Content types to generate
	 * @param array $product_info Product information
	 * @param string $language Target language
	 * @param string $style_description Writing style description
	 * @param array $options Additional options
	 * @return array System and user prompts
	 */
	private function buildUnifiedPrompt( array $content_types, array $product_info, string $language, string $style_description, array $options ): array {
		$max_length       = get_option( 'aipt_max_length', Activator::get_default_value( 'max_length' ) );
		$max_short_length = get_option( 'aipt_max_short_length', Activator::get_default_value( 'max_short_length' ) );
		$max_tags_count   = get_option( 'aipt_max_tags_count', 5 );

		$system_prompt = "You are an expert e-commerce content writer. Your task is to generate high-quality, SEO-optimized product content.\n\n";
		$system_prompt .= "CRITICAL RULES:\n";
		$system_prompt .= "1. You are writing content ONLY for this specific product: \"{$product_info['name']}\"\n";
		$system_prompt .= "2. DO NOT reference, mention, or include information about any other products\n";
		$system_prompt .= "3. All content must be consistent and complementary - the short description should summarize the full description\n";
		$system_prompt .= "4. Write in {$language} language\n";
		$system_prompt .= "5. Use this writing style: {$style_description}\n";
		$system_prompt .= "6. Format descriptions as HTML (use <p>, <ul>, <li>, <strong>, etc.). Do NOT use Markdown.\n";
		$system_prompt .= "7. NEVER include literal prices, price ranges, or currency amounts in any generated content. Prices change frequently and make descriptions outdated.\n\n";

		$system_prompt .= "You will generate the following content types:\n";
		
		if ( in_array( self::TYPE_DESCRIPTION, $content_types ) ) {
			$system_prompt .= "- FULL DESCRIPTION: Detailed product description (max {$max_length} words), formatted in HTML\n";
		}
		if ( in_array( self::TYPE_SHORT_DESCRIPTION, $content_types ) ) {
			$system_prompt .= "- SHORT DESCRIPTION: Brief product summary (max {$max_short_length} words), formatted in HTML\n";
		}
		if ( in_array( self::TYPE_TAGS, $content_types ) ) {
			$system_prompt .= "- TAGS: {$max_tags_count} relevant product tags, comma-separated, no hashtags\n";
		}
		if ( in_array( self::TYPE_TITLE, $content_types ) ) {
			$system_prompt .= "- TITLE: SEO-optimized product title (max 60 characters)\n";
		}

		$system_prompt .= "\nRESPONSE FORMAT:\n";
		$system_prompt .= "Return a valid JSON object with the following structure (only include requested types):\n";
		$system_prompt .= "{\n";
		
		$json_parts = [];
		if ( in_array( self::TYPE_DESCRIPTION, $content_types ) ) {
			$json_parts[] = '  "description": "<p>Full HTML description here...</p>"';
		}
		if ( in_array( self::TYPE_SHORT_DESCRIPTION, $content_types ) ) {
			$json_parts[] = '  "short_description": "<p>Short HTML description here...</p>"';
		}
		if ( in_array( self::TYPE_TAGS, $content_types ) ) {
			$json_parts[] = '  "tags": "tag1, tag2, tag3, tag4, tag5"';
		}
		if ( in_array( self::TYPE_TITLE, $content_types ) ) {
			$json_parts[] = '  "title": "SEO Product Title Here"';
		}
		
		$system_prompt .= implode( ",\n", $json_parts ) . "\n}\n";
		$system_prompt .= "\nIMPORTANT: Return ONLY the JSON object, no additional text or markdown code blocks.";

		$user_prompt = "Generate content for this product:\n\n";
		$user_prompt .= "PRODUCT NAME: {$product_info['name']}\n";
		
		if ( ! empty( $product_info['sku'] ) && $product_info['sku'] !== 'N/A' ) {
			$user_prompt .= "SKU: {$product_info['sku']}\n";
		}
		
		
		if ( ! empty( $product_info['categories'] ) ) {
			$user_prompt .= "CATEGORIES: " . implode( ', ', $product_info['categories'] ) . "\n";
		}
		
		if ( ! empty( $product_info['attributes'] ) ) {
			$attrs = [];
			foreach ( $product_info['attributes'] as $name => $value ) {
				$attrs[] = "{$name}: {$value}";
			}
			$user_prompt .= "ATTRIBUTES: " . implode( ', ', $attrs ) . "\n";
		}
		
		if ( ! empty( $product_info['existing_short_description'] ) ) {
			$user_prompt .= "EXISTING SHORT DESCRIPTION: {$product_info['existing_short_description']}\n";
		}

		if ( ! empty( $product_info['existing_description'] ) ) {
			$user_prompt .= "EXISTING DESCRIPTION: " . \wp_trim_words( $product_info['existing_description'], 100 ) . "\n";
		}

		$user_prompt .= "\nPlease generate the requested content types as a JSON object.";

		return [
			'system' => $system_prompt,
			'user'   => $user_prompt,
		];
	}

	/**
	 * Calculate max length based on content types
	 *
	 * @param array $content_types Content types being generated
	 * @return int Maximum token/word length
	 */
	private function calculateMaxLength( array $content_types ): int {
		$max_length       = (int) get_option( 'aipt_max_length', 500 );
		$max_short_length = (int) get_option( 'aipt_max_short_length', 150 );

		$total = 0;

		if ( in_array( self::TYPE_DESCRIPTION, $content_types ) ) {
			$total += $max_length;
		}
		if ( in_array( self::TYPE_SHORT_DESCRIPTION, $content_types ) ) {
			$total += $max_short_length;
		}
		if ( in_array( self::TYPE_TAGS, $content_types ) ) {
			$total += 100; 
		}
		if ( in_array( self::TYPE_TITLE, $content_types ) ) {
			$total += 50; 
		}

		$total += 200;

		return min( $total, 4000 ); 
	}

	/**
	 * Parse AI response into structured content
	 *
	 * @param string $response AI response text
	 * @param array $content_types Expected content types
	 * @return array Parsed content
	 */
	private function parseResponse( string $response, array $content_types ): array {

		$response = trim( $response );
		

		$response = preg_replace( '/^```json?\s*\n?/i', '', $response );
		$response = preg_replace( '/\n?```\s*$/i', '', $response );
		$response = trim( $response );

		$parsed = json_decode( $response, true );

		if ( json_last_error() === JSON_ERROR_NONE && is_array( $parsed ) ) {
			return $parsed;
		}

		$result = [];

		if ( preg_match( '/\{[^{}]*"(?:description|short_description|tags|title)"[^{}]*\}/s', $response, $matches ) ) {
			$parsed = json_decode( $matches[0], true );
			if ( json_last_error() === JSON_ERROR_NONE && is_array( $parsed ) ) {
				return $parsed;
			}
		}

		foreach ( $content_types as $type ) {
			$pattern = '/"' . preg_quote( $type, '/' ) . '"\s*:\s*"([^"]+)"/';
			if ( preg_match( $pattern, $response, $matches ) ) {
				$result[ $type ] = stripcslashes( $matches[1] );
			}
		}

		if ( ! empty( $result ) ) {
			return $result;
		}

		throw new \Exception( 'Failed to parse AI response. The response was not in the expected JSON format.' );
	}

	/**
	 * Post-process generated content
	 *
	 * @param array $parsed Parsed AI response
	 * @param array $content_types Content types that were requested
	 * @param \WC_Product $product Product instance
	 * @param array $options Generation options
	 * @return array Processed content
	 */
	private function postProcessContent( array $parsed, array $content_types, $product, array $options ): array {
		$result = [];

		if ( in_array( self::TYPE_DESCRIPTION, $content_types ) && isset( $parsed['description'] ) ) {
			$description = PromptFormatter::formatAiResponseForWordPress( $parsed['description'] );
			

			if ( ! empty( $options['keepExistingDescription'] ) ) {
				$existing = $product->get_description();
				if ( ! empty( $existing ) ) {
					$description = $existing . "\n\n" . $description;
				}
			}
			
			$result['description'] = $description;
		}

		if ( in_array( self::TYPE_SHORT_DESCRIPTION, $content_types ) && isset( $parsed['short_description'] ) ) {
			$short_description = PromptFormatter::formatAiResponseForWordPress( $parsed['short_description'] );
			

			if ( ! empty( $options['keepExistingShortDescription'] ) ) {
				$existing = $product->get_short_description();
				if ( ! empty( $existing ) ) {
					$short_description = $existing . "\n\n" . $short_description;
				}
			}
			
			$result['short_description'] = $short_description;
		}

		if ( in_array( self::TYPE_TAGS, $content_types ) && isset( $parsed['tags'] ) ) {
			$tags_text = $parsed['tags'];
			$tags = array_map( 'trim', explode( ',', $tags_text ) );
			$tags = array_filter( $tags, function( $tag ) {
				return ! empty( $tag ) && 
				       ! preg_match( '/[<>{}()\\[\\]\\/\\\\]/', $tag ) && 
				       strlen( $tag ) <= 100;
			});
			
			$max_tags = (int) get_option( 'aipt_max_tags_count', 5 );
			$tags = array_slice( $tags, 0, $max_tags );
			
			$result['tags'] = $tags;
			$result['tags_text'] = implode( ', ', $tags );
		}

		if ( in_array( self::TYPE_TITLE, $content_types ) && isset( $parsed['title'] ) ) {
			$title = sanitize_text_field( $parsed['title'] );

			if ( mb_strlen( $title, 'UTF-8' ) > 200 ) {
				$title = mb_substr( $title, 0, 197, 'UTF-8' ) . '...';
			}
			$result['title'] = $title;
		}

		return $result;
	}

	/**
	 * Get product information
	 *
	 * @param \WC_Product $product Product instance
	 * @return array Product information array
	 */
	private function getProductInfo( $product ): array {
		$categories = array_map(
			function( $term ) {
				return $term->name;
			},
			\get_the_terms( $product->get_id(), 'product_cat' ) ?: []
		);

		$tags = array_map(
			function( $term ) {
				return $term->name;
			},
			\get_the_terms( $product->get_id(), 'product_tag' ) ?: []
		);

		$attributes = [];
		foreach ( $product->get_attributes() as $attribute ) {
			if ( $attribute->is_taxonomy() ) {
				$terms = \get_the_terms( $product->get_id(), $attribute->get_name() );
				if ( $terms && ! \is_wp_error( $terms ) ) {
					$attributes[ \wc_attribute_label( $attribute->get_name() ) ] = implode(
						', ',
						array_map( function( $term ) { return $term->name; }, $terms )
					);
				}
			} else {
				$opts = $attribute->get_options();
				if ( is_array( $opts ) ) {
					$attributes[ \wc_attribute_label( $attribute->get_name() ) ] = implode( ', ', $opts );
				}
			}
		}

		return [
			'name'                       => $product->get_name(),
			'sku'                        => $product->get_sku() ?: 'N/A',
			'price'                      => \wc_price( $product->get_price() ),
			'regular_price'              => \wc_price( $product->get_regular_price() ),
			'sale_price'                 => $product->is_on_sale() ? \wc_price( $product->get_sale_price() ) : 'N/A',
			'categories'                 => $categories,
			'tags'                       => $tags,
			'attributes'                 => $attributes,
			'existing_short_description' => \wp_strip_all_tags( $product->get_short_description() ),
			'existing_description'       => \wp_strip_all_tags( $product->get_description() ),
		];
	}

	/**
	 * Get valid content types
	 *
	 * @return array
	 */
	public static function getValidTypes(): array {
		return self::$valid_types;
	}
}
