<?php
/**
 * Image ALT prompt builder.
 *
 * @package SmartyPress_AI_Engine
 */

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

/**
 * Builds strict prompts for image metadata generation.
 */
class SmartyPress_AI_Image_ALT_Prompt_Builder {

	/**
	 * Build a vision prompt for an attachment.
	 *
	 * @param array $context  SEO and attachment context.
	 * @param array $settings Module settings.
	 * @return string
	 */
	public function build( array $context, array $settings ) {
		$language = ! empty( $settings['language'] ) ? $settings['language'] : smartypress_ai_get_language_by_locale();
		if ( 'custom' === $language && ! empty( $settings['customLanguage'] ) ) {
			$language = $settings['customLanguage'];
		}
		$max_alt      = absint( $settings['max_alt_length'] ?? 125 );
		$max_alt      = $max_alt > 0 ? $max_alt : 125;
		$manual_key   = sanitize_text_field( $settings['manual_focus_keyword'] ?? '' );
		$keywords     = ! empty( $settings['include_seo_keyword'] ) ? ( $context['focus_keywords'] ?? array() ) : array();
		$keywords     = ! empty( $manual_key ) ? array( $manual_key ) : $keywords;
		$primary_post = $context['primary_post'] ?? null;

		$lines = array(
			'You are an SEO image metadata assistant for WordPress.',
			'Analyze the attached image and generate accurate metadata.',
			'Return only valid JSON with keys: alt, caption, title, description.',
			'Do not include Markdown, explanations, quotes around the JSON, or extra keys.',
			'Do not invent visible text, brands, people, places, or facts that are not visible or supported by the context.',
			sprintf( 'Write in %s.', $language ),
			sprintf( 'ALT text must be natural, descriptive, concise, and no longer than %d characters.', $max_alt ),
			'Caption may be a short human-readable sentence when caption generation is enabled.',
			'Title should be short and start with a capital letter.',
			'Description should be one concise sentence.',
			'If SEO keywords are relevant to the actual image, include them naturally. Do not force irrelevant keywords.',
			'',
			'Context:',
			'- Attachment title: ' . ( $context['attachment_title'] ?: 'n/a' ),
			'- File name: ' . ( $context['filename'] ?: 'n/a' ),
			'- Current alt: ' . ( $context['current_alt'] ?: 'empty' ),
			'- Current caption: ' . ( $context['current_caption'] ?: 'empty' ),
			'- SEO focus keywords: ' . ( ! empty( $keywords ) ? implode( ', ', array_slice( $keywords, 0, 3 ) ) : 'n/a' ),
		);

		if ( is_array( $primary_post ) ) {
			$lines[] = '- Related post title: ' . ( $primary_post['title'] ?? 'n/a' );
			$lines[] = '- Related post type: ' . ( $primary_post['type'] ?? 'n/a' );
		}

		if ( ! empty( $context['related_posts'] ) ) {
			$titles = array();
			foreach ( $context['related_posts'] as $post ) {
				if ( ! empty( $post['title'] ) ) {
					$titles[] = $post['title'];
				}
			}
			if ( ! empty( $titles ) ) {
				$lines[] = '- Other related titles: ' . implode( ' | ', array_slice( $titles, 0, 3 ) );
			}
		}

		$lines[] = '';
		$lines[] = 'JSON example: {"alt":"Short descriptive alt text","caption":"Short caption","title":"Image title","description":"One sentence description"}';

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

	/**
	 * Build prompt for the vision model to describe the image only.
	 *
	 * @param array $context  SEO and attachment context.
	 * @param array $settings Module settings.
	 * @return string
	 */
	public function build_visual_description_prompt( array $context, array $settings ) {
		$primary_post = $context['primary_post'] ?? null;
		$lines        = array(
			'Analyze the attached image for WordPress SEO metadata generation.',
			'Return a concise plain-text visual description only.',
			'Do not generate ALT, caption, title, description, JSON, Markdown, or explanations.',
			'Describe only visible content. Do not invent brands, people, places, or text that are not visible.',
			'',
			'Context that may help interpret the image:',
			'- Attachment title: ' . ( $context['attachment_title'] ?: 'n/a' ),
			'- File name: ' . ( $context['filename'] ?: 'n/a' ),
		);

		if ( is_array( $primary_post ) ) {
			$lines[] = '- Related post title: ' . ( $primary_post['title'] ?? 'n/a' );
			$lines[] = '- Related post type: ' . ( $primary_post['type'] ?? 'n/a' );
		}

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

	/**
	 * Build final metadata prompt for the text model.
	 *
	 * @param array  $context            SEO and attachment context.
	 * @param array  $settings           Module settings.
	 * @param string $visual_description Image description from the vision model.
	 * @return string
	 */
	public function build_metadata_prompt( array $context, array $settings, $visual_description = '', array $strategy_context = array() ) {
		$language = ! empty( $settings['language'] ) ? $settings['language'] : smartypress_ai_get_language_by_locale();
		if ( 'custom' === $language && ! empty( $settings['customLanguage'] ) ) {
			$language = $settings['customLanguage'];
		}

		$max_alt      = absint( $settings['max_alt_length'] ?? 125 );
		$max_alt      = $max_alt > 0 ? $max_alt : 125;
		$manual_key   = sanitize_text_field( $settings['manual_focus_keyword'] ?? '' );
		$keywords     = ! empty( $settings['include_seo_keyword'] ) ? ( $context['focus_keywords'] ?? array() ) : array();
		$keywords     = ! empty( $manual_key ) ? array( $manual_key ) : $keywords;
		$primary_post = $context['primary_post'] ?? null;
		$json_keys    = $this->get_requested_json_keys( $settings );

		$lines = array(
			'You are an SEO image metadata assistant for WordPress.',
			'Generate final metadata from the image description and context.',
			'Return only valid JSON with keys: ' . implode( ', ', $json_keys ) . '.',
			'Do not include Markdown, explanations, quotes around the JSON, or extra keys.',
			'Do not invent visible text, brands, people, places, or facts that are not supported by the image description or context.',
			sprintf( 'Write in %s.', $language ),
			sprintf( 'ALT text must be natural, descriptive, concise, and no longer than %d characters.', $max_alt ),
			'Caption may be a short human-readable sentence when caption generation is enabled.',
			'Title should be short and start with a capital letter.',
			'Description should be one concise sentence.',
			'If SEO keywords are relevant to the image description or context, include them naturally. Do not force irrelevant keywords.',
			'',
			'Image description:',
			'' !== trim( (string) $visual_description ) ? $visual_description : 'n/a',
			'',
			'Context:',
			'- Attachment title: ' . ( $context['attachment_title'] ?: 'n/a' ),
			'- File name: ' . ( $context['filename'] ?: 'n/a' ),
			'- Current alt: ' . ( $context['current_alt'] ?: 'empty' ),
			'- Current caption: ' . ( $context['current_caption'] ?: 'empty' ),
			'- Current description: ' . ( $context['current_description'] ?: 'empty' ),
			'- SEO focus keywords: ' . ( ! empty( $keywords ) ? implode( ', ', array_slice( $keywords, 0, 3 ) ) : 'n/a' ),
		);

		if ( is_array( $primary_post ) ) {
			$lines[] = '- Related post title: ' . ( $primary_post['title'] ?? 'n/a' );
			$lines[] = '- Related post type: ' . ( $primary_post['type'] ?? 'n/a' );
			$lines[] = '- Related post excerpt: ' . ( $primary_post['excerpt'] ?? 'n/a' );
			$lines[] = '- Related post taxonomy terms: ' . ( $primary_post['taxonomies'] ?? 'n/a' );
		}

		if ( ! empty( $context['related_posts'] ) ) {
			$titles = array();
			foreach ( $context['related_posts'] as $post ) {
				if ( ! empty( $post['title'] ) ) {
					$titles[] = $post['title'];
				}
			}
			if ( ! empty( $titles ) ) {
				$lines[] = '- Other related titles: ' . implode( ' | ', array_slice( $titles, 0, 3 ) );
			}
		}

		$lines[] = '';
		$lines[] = 'Strategy: ' . ( $strategy_context['strategy'] ?? 'vision_two_step' ) . '. Confidence: ' . ( $strategy_context['confidence'] ?? 'high' ) . '.';
		$lines[] = 'JSON example: ' . $this->build_json_example( $settings );

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

	/**
	 * Build prompt without sending image bytes to the AI provider.
	 *
	 * @param array $context  SEO and attachment context.
	 * @param array $settings Module settings.
	 * @return string
	 */
	public function build_context_only( array $context, array $settings, array $strategy_context = array() ) {
		$language = ! empty( $settings['language'] ) ? $settings['language'] : smartypress_ai_get_language_by_locale();
		if ( 'custom' === $language && ! empty( $settings['customLanguage'] ) ) {
			$language = $settings['customLanguage'];
		}

		$max_alt      = absint( $settings['max_alt_length'] ?? 125 );
		$max_alt      = $max_alt > 0 ? $max_alt : 125;
		$manual_key   = sanitize_text_field( $settings['manual_focus_keyword'] ?? '' );
		$keywords     = ! empty( $settings['include_seo_keyword'] ) ? ( $context['focus_keywords'] ?? array() ) : array();
		$keywords     = ! empty( $manual_key ) ? array( $manual_key ) : $keywords;
		$primary_post = $context['primary_post'] ?? null;
		$json_keys    = $this->get_requested_json_keys( $settings );
		$strategy     = $strategy_context['strategy'] ?? 'context_existing_metadata';

		if ( 'poor_custom_prompt' === $strategy ) {
			return $this->build_poor_context_prompt( $context, $settings, $strategy_context );
		}

		$lines = array(
			'You are an SEO image metadata assistant for WordPress.',
			'Generate image metadata without seeing the actual image.',
			'Use only the attachment title, file name, related post title, SEO keywords, and existing metadata as context.',
			'Do not invent visual details, brands, people, places, objects, or facts that are not supported by the context.',
			'If the exact visual content is unclear, write cautious metadata based on the file name and article context.',
			'Return only valid JSON with keys: ' . implode( ', ', $json_keys ) . '.',
			'Do not include Markdown, explanations, quotes around the JSON, or extra keys.',
			sprintf( 'Write in %s.', $language ),
			sprintf( 'ALT text must be natural, descriptive, concise, and no longer than %d characters.', $max_alt ),
			'Caption may be a short human-readable sentence when caption generation is enabled.',
			'Title should be short and start with a capital letter.',
			'Description should be one concise sentence.',
			'If SEO keywords are relevant to the available context, include them naturally. Do not force irrelevant keywords.',
			'',
			'Context:',
			'- Attachment title: ' . ( $context['attachment_title'] ?: 'n/a' ),
			'- File name: ' . ( $context['filename'] ?: 'n/a' ),
			'- Current alt: ' . ( $context['current_alt'] ?: 'empty' ),
			'- Current caption: ' . ( $context['current_caption'] ?: 'empty' ),
			'- Current description: ' . ( $context['current_description'] ?: 'empty' ),
			'- SEO focus keywords: ' . ( ! empty( $keywords ) ? implode( ', ', array_slice( $keywords, 0, 3 ) ) : 'n/a' ),
		);

		if ( is_array( $primary_post ) ) {
			$lines[] = '- Related post title: ' . ( $primary_post['title'] ?? 'n/a' );
			$lines[] = '- Related post type: ' . ( $primary_post['type'] ?? 'n/a' );
			$lines[] = '- Related post excerpt: ' . ( $primary_post['excerpt'] ?? 'n/a' );
			$lines[] = '- Related post taxonomy terms: ' . ( $primary_post['taxonomies'] ?? 'n/a' );
		}

		if ( ! empty( $context['related_posts'] ) ) {
			$titles = array();
			foreach ( $context['related_posts'] as $post ) {
				if ( ! empty( $post['title'] ) ) {
					$titles[] = $post['title'];
				}
			}
			if ( ! empty( $titles ) ) {
				$lines[] = '- Other related titles: ' . implode( ' | ', array_slice( $titles, 0, 3 ) );
			}
		}

		$lines[] = '';
		$lines[] = $this->get_strategy_instruction( $strategy );
		$lines[] = 'Strategy: ' . $strategy . '. Confidence: ' . ( $strategy_context['confidence'] ?? 'low' ) . '.';
		$lines[] = 'JSON example: ' . $this->build_json_example( $settings );

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

	/**
	 * Build prompt for poor context using user-provided strategy.
	 *
	 * @param array $context          Attachment and SEO context.
	 * @param array $settings         Module settings.
	 * @param array $strategy_context Strategy metadata.
	 * @return string
	 */
	private function build_poor_context_prompt( array $context, array $settings, array $strategy_context ) {
		$language = ! empty( $settings['language'] ) ? $settings['language'] : smartypress_ai_get_language_by_locale();
		if ( 'custom' === $language && ! empty( $settings['customLanguage'] ) ) {
			$language = $settings['customLanguage'];
		}

		$max_alt     = absint( $settings['max_alt_length'] ?? 125 );
		$max_alt     = $max_alt > 0 ? $max_alt : 125;
		$user_prompt = trim( (string) ( $settings['poor_context_prompt'] ?? '' ) );
		$user_prompt = '' !== $user_prompt ? $user_prompt : 'Generate cautious, generic WordPress image metadata from the available filename and attachment metadata. Do not invent specific visual details.';
		$user_prompt = $this->replace_prompt_variables( $user_prompt, $context, $settings );

		return implode(
			"\n",
			array(
				'You are an SEO image metadata assistant for WordPress.',
				'The image has poor context and the actual image is not visible.',
				'Follow this user-defined poor-context strategy:',
				$user_prompt,
				'',
				'Hard requirements:',
				'Return only valid JSON with keys: ' . implode( ', ', $this->get_requested_json_keys( $settings ) ) . '.',
				'Do not include Markdown, explanations, quotes around the JSON, or extra keys.',
				sprintf( 'Write in %s.', $language ),
				sprintf( 'ALT text must be natural, cautious, concise, and no longer than %d characters.', $max_alt ),
				'Do not invent visual details, brands, people, places, objects, or facts that are not supported by context.',
				'',
				'Available context:',
				'- Attachment title: ' . ( $context['attachment_title'] ?: 'n/a' ),
				'- File name: ' . ( $context['filename'] ?: 'n/a' ),
				'- Current alt: ' . ( $context['current_alt'] ?: 'empty' ),
				'- Current caption: ' . ( $context['current_caption'] ?: 'empty' ),
				'- Current description: ' . ( $context['current_description'] ?: 'empty' ),
				'',
				'Strategy: ' . ( $strategy_context['strategy'] ?? 'poor_custom_prompt' ) . '. Confidence: ' . ( $strategy_context['confidence'] ?? 'low' ) . '. Review recommended.',
				'JSON example: ' . $this->build_json_example( $settings ),
			)
		);
	}

	/**
	 * Return strategy-specific instruction.
	 *
	 * @param string $strategy Strategy key.
	 * @return string
	 */
	private function get_strategy_instruction( $strategy ) {
		$instructions = array(
			'context_post_keyword'      => 'Use the related post and SEO keyword as primary context, but include the keyword only when it reads naturally.',
			'context_post'              => 'Use the related post title, excerpt, taxonomy terms, filename and attachment metadata as context.',
			'context_existing_metadata' => 'Use existing attachment metadata and filename cautiously. Avoid specific visual claims that are not supported.',
		);

		return $instructions[ $strategy ] ?? $instructions['context_existing_metadata'];
	}

	/**
	 * Get enabled JSON keys.
	 *
	 * @param array $settings Module settings.
	 * @return array
	 */
	private function get_requested_json_keys( array $settings ) {
		if ( ! empty( $settings['requested_fields'] ) && is_array( $settings['requested_fields'] ) ) {
			$allowed = array( 'alt', 'caption', 'title', 'description' );
			$fields  = array_values( array_intersect( $allowed, array_map( 'sanitize_key', $settings['requested_fields'] ) ) );

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

		$keys = array();

		if ( ! empty( $settings['generate_alt'] ) ) {
			$keys[] = 'alt';
		}
		if ( ! empty( $settings['generate_caption'] ) ) {
			$keys[] = 'caption';
		}
		if ( ! empty( $settings['generate_title'] ) ) {
			$keys[] = 'title';
		}
		if ( ! empty( $settings['generate_description'] ) ) {
			$keys[] = 'description';
		}

		return ! empty( $keys ) ? $keys : array( 'alt' );
	}

	/**
	 * Build compact JSON example for enabled keys.
	 *
	 * @param array $settings Module settings.
	 * @return string
	 */
	private function build_json_example( array $settings ) {
		$examples = array(
			'alt'         => 'Short descriptive alt text',
			'caption'     => 'Short caption',
			'title'       => 'Image title',
			'description' => 'One sentence description',
		);
		$data     = array();

		foreach ( $this->get_requested_json_keys( $settings ) as $key ) {
			$data[ $key ] = $examples[ $key ];
		}

		return wp_json_encode( $data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
	}

	/**
	 * Replace safe variables in custom poor context prompt.
	 *
	 * @param string $prompt   Prompt.
	 * @param array  $context  Context.
	 * @param array  $settings Settings.
	 * @return string
	 */
	private function replace_prompt_variables( $prompt, array $context, array $settings ) {
		$language = ! empty( $settings['language'] ) ? $settings['language'] : smartypress_ai_get_language_by_locale();
		if ( 'custom' === $language && ! empty( $settings['customLanguage'] ) ) {
			$language = $settings['customLanguage'];
		}

		$replacements = array(
			'{filename}'         => $context['filename'] ?? '',
			'{attachment_title}' => $context['attachment_title'] ?? '',
			'{site_name}'        => get_bloginfo( 'name' ),
			'{language}'         => $language,
		);

		return strtr( $prompt, $replacements );
	}
}
