<?php
/**
 * Content Generation Service
 *
 * Handles AI content generation for single products (descriptions, titles, tags).
 *
 * @package AIPT\Api\Services
 * @since 2.4.1
 */

namespace AIPT\Api\Services;

use AIPT\Api\BulkGenerator\Title\TitleGeneratorService;
use AIPT\Core\Activator;
use AIPT\Core\ErrorHandler;
use AIPT\Utils\VariableConverter;
use AIPT\Utils\PromptFormatter;

/**
 * Content Generation Service Implementation
 *
 * Generates AI-powered product descriptions, titles, and tags for single products.
 *
 * @internal Used by RestEndpoints
 */
class ContentGenerationService {

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

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

	/**
	 * 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;
	}

	/**
	 * Generate product description
	 *
	 * @param array $params Generation parameters (product_id, is_short, improveExistingDescription, keepExistingDescription)
	 * @return array|\WP_Error Generated content or error
	 */
	public function generateDescription( array $params ) {
		try {
			$api_provider = get_option( 'aipt_api_provider', 'openai' );
			$product_id   = $params['product_id'];
			$is_short     = isset( $params['is_short'] ) ? $params['is_short'] : false;

			$model   = $this->ai_client_factory->getDefaultModel( $api_provider );
			$model   = get_option( 'aipt_model', $model );
			$model   = $this->ai_client_factory->normalizeModel( $api_provider, $model );
			$product = wc_get_product( $product_id );

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

			$language      = get_option( 'aipt_language', Activator::get_default_value( 'language' ) );
			$writing_style = get_option( 'aipt_writing_style', Activator::get_default_value( 'writing_style' ) );
			$max_length    = (int) ( $is_short ?
				get_option( 'aipt_max_short_length', Activator::get_default_value( 'max_short_length' ) ) :
				get_option( 'aipt_max_length', Activator::get_default_value( 'max_length' ) ) );

			$legacy_system_prompt = get_option( 'aipt_system_prompt', Activator::get_default_value( 'system_prompt' ) );
			$legacy_user_prompt   = get_option( 'aipt_user_prompt', Activator::get_default_value( 'user_prompt' ) );

			$short_system_prompt = get_option( 'aipt_short_system_prompt', $legacy_system_prompt );
			$short_user_prompt   = get_option( 'aipt_short_user_prompt', $legacy_user_prompt );
			$full_system_prompt  = get_option( 'aipt_full_system_prompt', $legacy_system_prompt );
			$full_user_prompt    = get_option( 'aipt_full_user_prompt', $legacy_user_prompt );

			$system_prompt = $is_short ? $short_system_prompt : $full_system_prompt;
			$user_prompt   = $is_short ? $short_user_prompt : $full_user_prompt;

			$style_description = isset( $this->style_descriptions[ $writing_style ] )
				? $this->style_descriptions[ $writing_style ]
				: $this->style_descriptions['Professional'];

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

			$attributes_string = ! empty( $product_info['attributes'] )
				? implode( ', ', array_map(
					function ( $k, $v ) {
						return "$k: $v";
					},
					array_keys( $product_info['attributes'] ),
					$product_info['attributes']
				) )
				: '';
			$categories_string = implode( ', ', $product_info['categories'] );
			$tags_string       = implode( ', ', $product_info['tags'] );

			$safe_variables = VariableConverter::convertVariables(
				array(
					'{max_length}'    => intval( $max_length ),
					'{SKU}'           => $product_info['sku'],
					'{ATTRIBUTES}'    => $attributes_string,
					'{CATEGORIES}'    => $categories_string,
					'{TAGS}'          => $tags_string,
					'{PRICE}'         => $product_info['price'],
					'{REGULAR_PRICE}' => $product_info['regular_price'],
					'{SALE_PRICE}'    => $product_info['sale_price'],
					'{language}'      => sanitize_text_field( $language ),
					'{style}'         => sanitize_text_field( $style_description ),
					'{title}'         => $product_info['name'],
				)
			);

			$system_prompt = str_replace( array_keys( $safe_variables ), array_values( $safe_variables ), $system_prompt );
			$user_prompt   = str_replace( array_keys( $safe_variables ), array_values( $safe_variables ), $user_prompt );

			$client = $this->ai_client_factory->create();

			$system_prompt = $this->cleanPromptContent( $system_prompt, $product_info );
			$user_prompt   = $this->cleanPromptContent( $user_prompt, $product_info );

			$system_prompt .= " Ensure the output is formatted in HTML (using <p>, <ul>, <li>, <strong>, etc.). Do not use Markdown.";
			$system_prompt .= " NEVER include literal prices, price ranges, or currency amounts in the description. Prices change frequently and make descriptions outdated.";

			if ( isset( $params['improveExistingDescription'] ) && $params['improveExistingDescription'] ) {
				$existing_description = $is_short ? $product->get_short_description() : $product->get_description();
				if ( ! empty( $existing_description ) ) {
					$existing_description = wp_strip_all_tags( $existing_description );
					$user_prompt         .= "\n\nYOU SHOULD CONSIDER THE EXISTING PRODUCT DESCRIPTION: " . $existing_description;
				}
			}

			$description = $client->generate_description( $system_prompt, $user_prompt, $model, $max_length );

			$formatted_description = PromptFormatter::formatAiResponseForWordPress( $description );

			if ( isset( $params['keepExistingDescription'] ) && $params['keepExistingDescription'] ) {
				$existing_description = $is_short ? $product->get_short_description() : $product->get_description();
				if ( ! empty( $existing_description ) ) {
					$formatted_description = $existing_description . "\n\n" . $formatted_description;
				}
			}

			return array( 'description' => $formatted_description );
		} catch ( \Throwable $e ) {

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

	/**
	 * Generate product title
	 *
	 * @param array $params Generation parameters (product_id, max_length, keywords, tone, mode, titleSources)
	 * @return array|\WP_Error Generated title or error
	 */
	public function generateTitle( array $params ) {
		try {
			$product_id = $params['product_id'];
			$product    = wc_get_product( $product_id );

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

			$title_service = new TitleGeneratorService();

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

			$options = array(
				'provider'     => $provider,
				'model'        => $selected_model,
				'variantCount' => 1,
				'maxLength'    => $params['max_length'] ?? 60,
				'keywords'     => $params['keywords'] ?? '',
				'tone'         => $params['tone'] ?? 'SEO-Focused',
				'mode'         => $params['mode'] ?? 'rewrite',
				'titleSources' => $params['titleSources'] ?? array( 'product_description' ),
			);

			$results = $title_service->bulk_generate( array( $product_id ), $options );

			if ( empty( $results ) || ! isset( $results[0] ) ) {
				throw new \Exception( 'Title generation failed to produce a result.' );
			}

			$result = $results[0];

			if ( ! empty( $result['error'] ) ) {
				throw new \Exception( $result['error'] );
			}

			if ( empty( $result['text'] ) ) {
				throw new \Exception( 'No valid title was generated.' );
			}

			return array( 'title' => $result['text'] );
		} catch ( \Throwable $e ) {

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

	/**
	 * Generate product tags
	 *
	 * @param array $params Generation parameters (product_id, max_tags, keep_existing)
	 * @return array|\WP_Error Generated tags or error
	 */
	public function generateTags( array $params ) {
		try {
			$api_provider   = get_option( 'aipt_api_provider', 'openai' );
			$product_id     = $params['product_id'];
			$max_tags       = $params['max_tags'] ?? 5;
			$keep_existing  = $params['keep_existing'] ?? false;

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

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

		$language      = get_option( 'aipt_language', Activator::get_default_value( 'language' ) );
		$product_info  = $this->getProductInfo( $product );

			$system_prompt = 'You are a professional e-commerce SEO expert specialized in creating relevant product tags that improve searchability and categorization. Your task is to generate accurate, specific, and search-friendly tags for products.';

			$user_prompt  = "Generate {max_tags} relevant product tags in {language} language for the following product. ";
			$user_prompt .= 'Tags should be specific, search-friendly, and help customers find this product. ';
			$user_prompt .= 'Include material, style, use case, and feature-based tags where applicable. ';
			$user_prompt .= "Return only the tags separated by commas, without any additional text or explanations.\n\n";

			if ( $keep_existing && ! empty( $product_info['tags'] ) ) {
				$user_prompt .= "Existing tags: {TAGS}\n";
				$user_prompt .= "Add new complementary tags that don't duplicate existing ones.\n\n";
			}

			$user_prompt .= "Product name: {title}\n";
			$user_prompt .= "Categories: {CATEGORIES}\n";
			$user_prompt .= "Attributes: {ATTRIBUTES}\n";
			$user_prompt .= "Short description: {short_description}\n";

			$variables = array( '{max_tags}', '{language}', '{title}', '{CATEGORIES}', '{ATTRIBUTES}', '{TAGS}', '{short_description}' );

			$values = array(
				$max_tags,
				$language,
				$product_info['name'],
				implode( ', ', $product_info['categories'] ),
				! empty( $product_info['attributes'] ) ? implode(
					', ',
					array_map(
						function ( $k, $v ) {
							return "$k: $v";
						},
						array_keys( $product_info['attributes'] ),
						$product_info['attributes']
					)
				) : '',
				implode( ', ', $product_info['tags'] ),
				$product_info['short_description'],
			);

			$system_prompt = str_replace( $variables, $values, $system_prompt );
			$user_prompt   = str_replace( $variables, $values, $user_prompt );

			$client = $this->ai_client_factory->create();

			$tags_text = $client->generate_description( $system_prompt, $user_prompt, $model, 200 );

			$tags = array_map( 'trim', explode( ',', $tags_text ) );
			$tags = array_filter(
				$tags,
				function ( $tag ) {
					return ! empty( $tag ) && ! preg_match( '/[<>{}()\\[\\]\\/\\\\]/', $tag ) && strlen( $tag ) <= 100;
				}
			);

			$tags = array_slice( $tags, 0, $max_tags );

			if ( empty( $tags ) ) {
				throw new \Exception( 'No valid tags were generated' );
			}

			return array(
				'tags'      => $tags,
				'tags_text' => implode( ', ', $tags ),
			);
		} catch ( \Throwable $e ) {

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

	/**
	 * Apply description to product
	 *
	 * @param int $product_id Product ID
	 * @param string $description Description content
	 * @param string $type Description type (full|short)
	 * @return array|\WP_Error Success response or error
	 */
	public function applyContent( int $product_id, string $description, string $type = 'full' ) {
		try {
			$product = wc_get_product( $product_id );
			if ( ! $product ) {
				return new \WP_Error( 'invalid_product', 'Invalid product ID', array( 'status' => 404 ) );
			}

			if ( $type === 'short' ) {
				$product->set_short_description( $description );
			} else {
				$product->set_description( $description );
			}

			$product->save();

			return array( 'success' => true );
		} catch ( \Throwable $e ) {
			return new \WP_Error( 'update_failed', esc_html($e->getMessage()), array( 'status' => 500 ) );
		}
	}

	/**
	 * 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' ) ?: array()
		);

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

		$attributes = array();
		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 {
				$attributes[ wc_attribute_label( $attribute->get_name() ) ] = implode( ', ', $attribute->get_options() );
			}
		}

		return array(
			'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,
			'short_description' => wp_strip_all_tags( $product->get_short_description() ),
		);
	}

	/**
	 * Clean prompt content
	 *
	 * @param string $prompt Prompt text
	 * @param array $product_info Product information
	 * @return string Cleaned prompt
	 */
	private function cleanPromptContent( string $prompt, array $product_info ): string {
		$formatted = trim( $prompt );
		$formatted = preg_replace( '/\s+/', ' ', $formatted );
		$formatted = preg_replace( '/\n+/', "\n", $formatted );
		return $formatted;
	}

}
