<?php
/**
 * Costudio_Admin_Ajax_Planning — planning CRUD endpoints.
 *
 * Handles save/get/delete for entries in wp_costudio_planning (editorial
 * ideas queue). Delegates persistence to Costudio_Planning model.
 *
 * Extracted from Costudio_Admin as part of Task 2 (PR 6 — Planning AJAX split).
 *
 * @package Contentosapp_Studio
 * @since   3.2.0
 */

defined( 'ABSPATH' ) || exit;

class Costudio_Admin_Ajax_Planning extends Costudio_Admin_Ajax_Base {

	/** @var self|null */
	private static ?self $instance = null;

	private function __construct() {}

	public static function get_instance(): self {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	public function register_hooks(): void {
		$this->register_ajax_actions(
			array(
				'costudio_save_plan',
				'costudio_get_plan',
				'costudio_delete_plan',
				'costudio_suggest_plan_titles',
			)
		);
	}

	/**
	 * Create or update a planning entry.
	 */
	public function ajax_costudio_save_plan(): void {
		$in = $this->read_request(
			array(
				'plan_id'      => 'int',
				'title'        => 'text',
				'keyword'      => 'text',
				'site_key'     => 'text',
				'category'     => 'text',
				'planned_date' => 'text',
				'priority'     => 'text',
				'status'       => 'text',
			)
		);

		$id   = $in['plan_id'];
		$data = array(
			'title'        => $in['title'],
			'keyword'      => $in['keyword'],
			'site_key'     => $in['site_key'],
			'category'     => $in['category'],
			'planned_date' => $in['planned_date'],
			'priority'     => $in['priority'] ?: 'medium',
			'status'       => $in['status'] ?: 'planned',
		);

		if ( empty( $data['keyword'] ) ) {
			wp_send_json_error( __( 'Keyword is required.', 'contentosapp-studio' ) );
		}

		if ( empty( $data['title'] ) || empty( $data['site_key'] ) ) {
			wp_send_json_error( __( 'Title and Site are required.', 'contentosapp-studio' ) );
		}

		if ( $id > 0 ) {
			Costudio_Planning::update( $id, $data );
			wp_send_json_success( array( 'id' => $id, 'updated' => true ) );
		} else {
			$new_id = Costudio_Planning::create( $data );
			wp_send_json_success( array( 'id' => $new_id, 'updated' => false ) );
		}
	}

	/**
	 * Fetch a single planning entry by id.
	 */
	public function ajax_costudio_get_plan(): void {
		$in   = $this->read_request( array( 'plan_id' => 'int' ), 'get' );
		$id   = $in['plan_id'];
		$plan = Costudio_Planning::find( $id );
		if ( ! $plan ) {
			wp_send_json_error( __( 'Plan not found.', 'contentosapp-studio' ) );
		}
		wp_send_json_success( (array) $plan );
	}

	/**
	 * Delete a planning entry.
	 */
	public function ajax_costudio_delete_plan(): void {
		$in = $this->read_request( array( 'plan_id' => 'int' ) );
		$id = $in['plan_id'];
		Costudio_Planning::delete( $id );
		wp_send_json_success();
	}

	/**
	 * Generate short title/angle suggestions for a planning keyword.
	 */
	public function ajax_costudio_suggest_plan_titles(): void {
		$in       = $this->read_request(
			array(
				'keyword'  => 'text',
				'site_key' => 'text',
				'category' => 'text',
			)
		);
		$keyword  = $in['keyword'];
		$site_key = $in['site_key'];
		$category = $in['category'];

		if ( mb_strlen( trim( $keyword ) ) < 4 ) {
			wp_send_json_error( __( 'Keyword is required.', 'contentosapp-studio' ), 400 );
		}

		$context   = $this->get_title_suggestion_context( $keyword, $site_key, $category );
		$cache_key = $this->get_title_suggestion_cache_key( $context );
		$cached    = get_transient( $cache_key );

		if ( is_array( $cached ) && ! empty( $cached['suggestions'] ) ) {
			wp_send_json_success(
				array(
					'suggestions' => array_values( array_slice( (array) $cached['suggestions'], 0, 3 ) ),
					'source'      => 'ai',
					'cached'      => true,
				)
			);
		}

		if ( ! $this->allow_title_suggestion_request() ) {
			wp_send_json_error( __( 'Too many attempts. Please wait a few minutes and try again.', 'contentosapp-studio' ), 429 );
		}

		try {
			$client = $this->make_title_suggestion_client( $context );
			$prompt = $this->build_title_suggestion_prompt( $context );
			$output = $client->generate( $prompt );

			$suggestions = $this->parse_title_suggestions( $output );
			if ( empty( $suggestions ) ) {
				wp_send_json_error( __( 'Could not generate title suggestions right now.', 'contentosapp-studio' ), 502 );
			}

			set_transient(
				$cache_key,
				array(
					'suggestions' => $suggestions,
					'created_at'   => time(),
				),
				12 * HOUR_IN_SECONDS
			);

			wp_send_json_success(
				array(
					'suggestions' => $suggestions,
					'source'      => 'ai',
					'cached'      => false,
				)
			);
		} catch ( Throwable $e ) {
			if ( function_exists( 'costudio_log' ) ) {
				costudio_log( 'planning.title_suggestions.failed', array( 'error' => $e->getMessage() ), 'warning' );
			}

			wp_send_json_error( __( 'Could not generate title suggestions right now.', 'contentosapp-studio' ), 502 );
		}
	}

	/**
	 * @return array<string,string>
	 */
	private function get_title_suggestion_context( string $keyword, string $site_key, string $category ): array {
		$settings = function_exists( 'costudio_settings' ) ? costudio_settings() : null;
		$provider = $settings ? (string) $settings->get( 'ai_provider', 'gemini' ) : 'gemini';
		$model    = $settings ? (string) $settings->get( 'ai_model', '' ) : '';
		$ai_mode  = $settings ? (string) $settings->get( 'ai_mode', 'contentos' ) : 'contentos';
		$locale   = class_exists( 'Costudio_Admin' ) ? Costudio_Admin::get_default_content_language() : get_locale();
		$site     = '';

		if ( '' !== $site_key && function_exists( 'costudio_sites' ) ) {
			$repo = costudio_sites();
			$cfg  = $repo ? $repo->get( $site_key ) : null;
			if ( is_array( $cfg ) ) {
				$site = function_exists( 'costudio_site_display_name' )
					? costudio_site_display_name( $cfg, $site_key )
					: (string) ( $cfg['name'] ?? $site_key );
			}
		}

		return array(
			'keyword'  => trim( $keyword ),
			'site_key' => $site_key,
			'site'     => trim( $site ),
			'category' => trim( $category ),
			'locale'   => $locale,
			'provider' => $provider,
			'model'    => $model,
			'ai_mode'  => $ai_mode,
		);
	}

	/**
	 * @param array<string,string> $context
	 */
	private function get_title_suggestion_cache_key( array $context ): string {
		$payload = array(
			'v'        => 1,
			'keyword'  => mb_strtolower( $context['keyword'] ?? '' ),
			'site_key' => $context['site_key'] ?? '',
			'category' => mb_strtolower( $context['category'] ?? '' ),
			'locale'   => $context['locale'] ?? '',
			'provider' => $context['provider'] ?? '',
			'model'    => $context['model'] ?? '',
			'ai_mode'  => $context['ai_mode'] ?? '',
		);

		return 'costudio_title_suggest_' . md5( wp_json_encode( $payload ) );
	}

	private function allow_title_suggestion_request(): bool {
		$user_id = get_current_user_id();
		$key     = 'costudio_title_suggest_rl_' . ( $user_id > 0 ? $user_id : 'anon' );
		$count   = (int) get_transient( $key );

		if ( $count >= 10 ) {
			return false;
		}

		set_transient( $key, $count + 1, 10 * MINUTE_IN_SECONDS );
		return true;
	}

	/**
	 * @param array<string,string> $context
	 */
	private function make_title_suggestion_client( array $context ): Costudio_AI_Client {
		$settings = function_exists( 'costudio_settings' ) ? costudio_settings() : null;
		$provider = $context['provider'] ?: 'gemini';
		$api_key  = $settings ? (string) $settings->get( 'ai_api_key', '' ) : '';
		$ai_mode  = $context['ai_mode'] ?? '';

		$use_contentos = ( 'contentos' === $ai_mode ) || ( '' === $api_key && 'byok' !== $ai_mode );
		if ( $use_contentos ) {
			$license_key = (string) get_option( 'costudio_license_key', '' );
			return new Costudio_ContentOS_Adapter( $license_key, $provider );
		}

		$model_defaults = array(
			'gemini' => 'gemini-2.5-flash',
			'openai' => 'gpt-4o',
			'claude' => 'claude-haiku-4-5-20251001',
		);
		$model = $context['model'] ?: ( $model_defaults[ $provider ] ?? 'gemini-2.5-flash' );

		if ( class_exists( 'Costudio_Rate_Limiter' ) ) {
			Costudio_Rate_Limiter::wait( $provider, $api_key );
		}

		switch ( $provider ) {
			case 'claude':
				$client = new Costudio_Claude_Adapter( $api_key, $model );
				break;
			case 'openai':
				$client = new Costudio_OpenAI_Adapter( $api_key, $model );
				break;
			default:
				$client = new Costudio_Gemini_Adapter( $api_key, $model, false );
				break;
		}

		if ( method_exists( $client, 'set_thinking_budget' ) ) {
			$client->set_thinking_budget( 0 );
		}

		return $client;
	}

	/**
	 * @param array<string,string> $context
	 */
	private function build_title_suggestion_prompt( array $context ): string {
		$site_line     = $context['site'] ? '- Destination site: ' . $context['site'] . "\n" : '';
		$category_line = $context['category'] ? '- Category: ' . $context['category'] . "\n" : '';

		return sprintf(
			"Generate exactly 3 SEO-friendly article title/angle suggestions.\n\nContext:\n- Language/locale: %s\n- Main keyword: \"%s\"\n%s%s\nRules:\n- Return only valid JSON.\n- Return format: [\"title 1\", \"title 2\", \"title 3\"]\n- Do not include markdown, numbering, explanations, or extra keys.\n- Each title must be clear, editorial, and useful as an H1.\n- Avoid clickbait and exaggerated promises.\n- Use the main keyword naturally when possible.\n- Keep each title under 90 characters.\n",
			$context['locale'] ?: 'pt_BR',
			$context['keyword'],
			$site_line,
			$category_line
		);
	}

	/**
	 * @return string[]
	 */
	private function parse_title_suggestions( string $output ): array {
		$text = trim( $output );
		$text = preg_replace( '/^```(?:json)?\s*/i', '', $text );
		$text = preg_replace( '/\s*```$/', '', (string) $text );

		$decoded = json_decode( $text, true );
		if ( null === $decoded ) {
			$start = strpos( $text, '[' );
			$end   = strrpos( $text, ']' );
			if ( false !== $start && false !== $end && $end > $start ) {
				$decoded = json_decode( substr( $text, $start, $end - $start + 1 ), true );
			}
		}

		if ( is_array( $decoded ) && isset( $decoded['titles'] ) && is_array( $decoded['titles'] ) ) {
			$decoded = $decoded['titles'];
		}

		if ( ! is_array( $decoded ) ) {
			$decoded = preg_split( '/\r\n|\r|\n/', $text );
		}

		$suggestions = array();
		foreach ( (array) $decoded as $item ) {
			if ( ! is_scalar( $item ) ) {
				continue;
			}

			$title = sanitize_text_field( (string) $item );
			$title = preg_replace( '/^\s*(?:[-*]|\d+[.)])\s*/', '', (string) $title );
			$title = trim( html_entity_decode( (string) $title, ENT_QUOTES, 'UTF-8' ) );

			if ( '' === $title || mb_strlen( $title ) < 8 ) {
				continue;
			}

			if ( mb_strlen( $title ) > 100 ) {
				$title = rtrim( mb_substr( $title, 0, 100 ), " \t\n\r\0\x0B.,;:-" );
			}

			$key = mb_strtolower( $title );
			if ( isset( $suggestions[ $key ] ) ) {
				continue;
			}

			$suggestions[ $key ] = $title;
			if ( count( $suggestions ) >= 3 ) {
				break;
			}
		}

		return array_values( $suggestions );
	}
}
