<?php
/**
 * SEO optimization service.
 *
 * @package SmartyPress_AI_Engine
 */

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

/**
 * Generates and normalizes SEO metadata for generated posts.
 */
class SmartyPress_AI_Content_Generator_SEO_Optimization_Service {

	/**
	 * Fallback metadata builder.
	 *
	 * @var SmartyPress_AI_Content_Generator_SEO_Generation_Metadata_Service
	 */
	private $metadata_service;

	/**
	 * Language policy service.
	 *
	 * @var SmartyPress_AI_Content_Generator_Generation_Language_Service
	 */
	private $language_service;

	/**
	 * Constructor.
	 *
	 * @param SmartyPress_AI_Content_Generator_SEO_Generation_Metadata_Service $metadata_service Metadata service.
	 * @param SmartyPress_AI_Content_Generator_Generation_Language_Service|null $language_service Language policy service.
	 */
	public function __construct( SmartyPress_AI_Content_Generator_SEO_Generation_Metadata_Service $metadata_service, $language_service = null ) {
		$this->metadata_service = $metadata_service;
		$this->language_service = $language_service instanceof SmartyPress_AI_Content_Generator_Generation_Language_Service ? $language_service : new SmartyPress_AI_Content_Generator_Generation_Language_Service();
	}

	/**
	 * Optimize generated post fields for SEO.
	 *
	 * @param mixed $provider AI provider.
	 * @param array $args Optimization args.
	 * @return array
	 */
	public function optimize( $provider, array $args ) {
		$post_data = $this->build_post_data( $args );

		if ( empty( $provider ) || ! method_exists( $provider, 'generate_content' ) ) {
			return $this->fallback( $post_data );
		}

		$prompt = $this->build_prompt( $args );
		$prompt = apply_filters( 'smartypress_ai_bulk_seo_optimization_prompt', $prompt, $args );

		$params = array(
			'system_prompt' => 'You are an SEO editor. Return only valid JSON. Do not include Markdown, comments, or prose outside JSON.',
			'temperature'   => (float) ( $args['temperature'] ?? 0.3 ),
			'max_tokens'    => 900,
		);

		if ( ! empty( $args['model'] ) ) {
			$params['model'] = sanitize_text_field( $args['model'] );
		}

		$result = $provider->generate_content( $prompt, $params );
		if ( empty( $result['success'] ) || empty( $result['content'] ) ) {
			return $this->fallback( $post_data );
		}

		$metadata = $this->parse_metadata_json( $result['content'] );
		if ( empty( $metadata ) ) {
			return $this->fallback( $post_data );
		}

		$post_data['seo_metadata'] = $metadata;
		$post_data['seo_keywords'] = $metadata['focus_keywords'] ?? array();
		$post_data                 = $this->metadata_service->normalize_post_data( $post_data );

		return array(
			'success'      => true,
			'source'       => 'ai',
			'seo_keywords' => $post_data['seo_metadata']['focus_keywords'] ?? array(),
			'seo_metadata' => $post_data['seo_metadata'],
		);
	}

	/**
	 * Build fallback SEO package.
	 *
	 * @param array $post_data Post data.
	 * @return array
	 */
	private function fallback( array $post_data ) {
		$post_data = $this->metadata_service->normalize_post_data( $post_data );

		return array(
			'success'      => true,
			'source'       => 'fallback',
			'seo_keywords' => $post_data['seo_metadata']['focus_keywords'] ?? array(),
			'seo_metadata' => $post_data['seo_metadata'] ?? array(),
		);
	}

	/**
	 * Build normalized post data from SEO args.
	 *
	 * @param array $args Args.
	 * @return array
	 */
	private function build_post_data( array $args ) {
		return array(
			'post_title'    => sanitize_text_field( $args['title'] ?? '' ),
			'post_content'  => wp_kses_post( $args['content'] ?? '' ),
			'post_excerpt'  => sanitize_textarea_field( $args['excerpt'] ?? '' ),
			'post_status'   => sanitize_key( $args['post_status'] ?? 'draft' ),
			'post_type'     => sanitize_key( $args['post_type'] ?? 'post' ),
			'seo_keywords'  => is_array( $args['seo_keywords'] ?? null ) ? $args['seo_keywords'] : array(),
			'seo_metadata'  => is_array( $args['seo_metadata'] ?? null ) ? $args['seo_metadata'] : array(),
		);
	}

	/**
	 * Build SEO prompt.
	 *
	 * @param array $args Args.
	 * @return string
	 */
	private function build_prompt( array $args ) {
		$language             = sanitize_text_field( $args['language'] ?? 'English' );
		$language_instruction = $this->language_service->get_output_language_instruction( $language, 'seo_metadata' );
		$rules                = array_filter( array_map( 'sanitize_text_field', (array) ( $args['seo_rules'] ?? array() ) ) );

		return sprintf(
			"Create SEO metadata for this generated WordPress post.\n\n%1\$s\n\nPost type: %2\$s\nSource topic: %3\$s\nTitle: %4\$s\nExcerpt: %5\$s\nContext: %6\$s\n\nPost content:\n%7\$s\n\nRules:\n- Choose one primary keyword and up to four secondary keywords.\n- Focus keywords must match the real article topic and user search intent.\n- SEO title must be natural and include the primary keyword when it reads naturally.\n- Meta description must be 120-155 characters when possible and include the primary keyword.\n- Slug must be short, lowercase, and readable.\n- Do not invent product prices, stock, warranty, shipping, or factual claims not present in the content.\n%8\$s\n\nReturn JSON only with this exact shape:\n{\"focus_keywords\":[\"...\"],\"primary_keyword\":\"...\",\"secondary_keywords\":[\"...\"],\"seo_title\":\"...\",\"meta_description\":\"...\",\"slug\":\"...\",\"content_suggestions\":[\"...\"]}",
			$language_instruction,
			sanitize_key( $args['post_type'] ?? 'post' ),
			sanitize_text_field( $args['topic'] ?? '' ),
			sanitize_text_field( $args['title'] ?? '' ),
			sanitize_textarea_field( $args['excerpt'] ?? '' ),
			sanitize_textarea_field( $args['context'] ?? '' ),
			wp_trim_words( wp_strip_all_tags( (string) ( $args['content'] ?? '' ) ), 900, '' ),
			! empty( $rules ) ? "\nAdditional post type rules:\n- " . implode( "\n- ", $rules ) : ''
		);
	}

	/**
	 * Parse metadata JSON from provider response.
	 *
	 * @param string $content Provider response.
	 * @return array
	 */
	private function parse_metadata_json( $content ) {
		$json = trim( (string) $content );

		if ( preg_match( '/```(?:json)?\s*(.*?)```/is', $json, $matches ) ) {
			$json = trim( $matches[1] );
		} elseif ( 0 !== strpos( ltrim( $json ), '{' ) ) {
			$json = $this->extract_first_json_object( $json );
		}

		$data = json_decode( $json, true );
		if ( ! is_array( $data ) ) {
			return array();
		}

		$focus_keywords = $this->sanitize_string_list( $data['focus_keywords'] ?? array() );
		$primary        = sanitize_text_field( $data['primary_keyword'] ?? ( $focus_keywords[0] ?? '' ) );

		if ( '' !== $primary && empty( $focus_keywords ) ) {
			$focus_keywords[] = $primary;
		}

		return array(
			'seo_title'          => sanitize_text_field( $data['seo_title'] ?? '' ),
			'meta_description'   => sanitize_textarea_field( $data['meta_description'] ?? '' ),
			'slug'               => sanitize_title( $data['slug'] ?? '' ),
			'focus_keywords'     => array_values( array_slice( $focus_keywords, 0, 5 ) ),
			'primary_keyword'    => $primary,
			'secondary_keywords' => array_values( array_slice( $this->sanitize_string_list( $data['secondary_keywords'] ?? array() ), 0, 4 ) ),
		);
	}

	/**
	 * Extract first JSON object from text.
	 *
	 * @param string $content Content.
	 * @return string
	 */
	private function extract_first_json_object( $content ) {
		$start = strpos( $content, '{' );
		$end   = strrpos( $content, '}' );

		if ( false === $start || false === $end || $end <= $start ) {
			return '';
		}

		return substr( $content, $start, $end - $start + 1 );
	}

	/**
	 * Sanitize list of strings.
	 *
	 * @param mixed $items Items.
	 * @return array
	 */
	private function sanitize_string_list( $items ) {
		if ( is_string( $items ) ) {
			$items = preg_split( '/\r\n|\r|\n|,/', $items );
		}

		if ( ! is_array( $items ) ) {
			return array();
		}

		$clean = array();
		foreach ( $items as $item ) {
			if ( is_scalar( $item ) ) {
				$value = trim( preg_replace( '/\s+/u', ' ', sanitize_text_field( (string) $item ) ) );
				if ( '' !== $value ) {
					$clean[] = $value;
				}
			}
		}

		return array_values( array_unique( $clean ) );
	}
}
