<?php
/**
 * Settings storage with encrypted API keys.
 *
 * @package CatalogPilot\AiStudio
 */

namespace CatalogPilot\AiStudio;

defined( 'ABSPATH' ) || exit;

final class Settings {

	const OPTION_KEY = 'cpais_settings';

	private static $instance = null;

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

	public static function defaults() {
		return array(
			'active_provider'    => 'openai',
			'openai_api_key'     => '',
			'openai_model'       => 'gpt-4o-mini',
			'anthropic_api_key'  => '',
			'anthropic_model'    => 'claude-haiku-4-5',
			'gemini_api_key'     => '',
			'gemini_model'       => 'gemini-2.5-flash',
			'mistral_api_key'    => '',
			'mistral_model'      => 'mistral-small-latest',
			'deepseek_api_key'   => '',
			'deepseek_model'     => 'deepseek-chat',
			'grok_api_key'       => '',
			'grok_model'         => 'grok-3-mini',
			'groq_api_key'       => '',
			'groq_model'         => 'llama-3.3-70b-versatile',
			'openrouter_api_key' => '',
			'openrouter_model'   => 'openai/gpt-4o-mini',
			'perplexity_api_key' => '',
			'perplexity_model'   => 'sonar',

			'default_tone'       => 'professional',
			'default_length'     => 'medium',
			'default_language'   => 'en',

			// Cache + consent + cleanup.
			'cache_enabled'       => 1,
			'cache_ttl'           => 21600,
			'privacy_consent'     => 1,
			'delete_data_on_uninstall' => 0,

			// FAQ / Schema.
			'faq_schema_enabled'  => 1,
			'faq_default_count'   => 5,

			// Review summary.
			'review_summary_display' => 0, // off by default — themes vary, opt-in.
			'review_min_count'       => 3,

			// Background remover (uses Replicate API key).
			'bg_remover_model'       => '851-labs/background-remover',

			// Image providers.
			'active_image_provider'       => 'openai',
			'image_openai_api_key'        => '',
			'image_openai_model'          => 'gpt-image-1',
			'image_replicate_api_key'     => '',
			'image_replicate_model'       => 'black-forest-labs/flux-schnell',
			'image_gemini_api_key'        => '',
			'image_gemini_model'          => 'imagen-3.0-generate-002',
			'image_stability_api_key'     => '',
			'image_stability_model'       => 'stable-diffusion-xl-1024-v1-0',
		);
	}

	public static function text_provider_ids() {
		return array( 'openai', 'anthropic', 'gemini', 'mistral', 'deepseek', 'grok', 'groq', 'openrouter', 'perplexity' );
	}

	public static function get_all() {
		$stored = get_option( self::OPTION_KEY, array() );
		if ( ! is_array( $stored ) ) {
			$stored = array();
		}
		$settings = wp_parse_args( $stored, self::defaults() );

		foreach ( self::key_fields() as $field ) {
			$settings[ $field ] = self::decrypt( $settings[ $field ] );
		}

		return $settings;
	}

	public static function get( $key, $default = '' ) {
		$all = self::get_all();
		return isset( $all[ $key ] ) ? $all[ $key ] : $default;
	}

	/**
	 * Resolve the target language for AI generation.
	 *
	 * Auto-detects WPML and Polylang when active; otherwise falls back to the
	 * user-selected default_language in Settings, and finally to the WordPress
	 * locale. The result is filterable so themes / MU-plugins can override.
	 *
	 * @param int $post_id Optional post ID (used to pull per-post language).
	 * @return string Two-letter language code (e.g. 'en', 'tr', 'de') or a full
	 *                locale if WPML/Polylang exposes it.
	 */
	public static function resolve_language( $post_id = 0 ) {
		$lang = '';

		if ( $post_id > 0 && function_exists( 'pll_get_post_language' ) ) {
			$lang = (string) pll_get_post_language( $post_id, 'slug' );
		}
		if ( '' === $lang && function_exists( 'pll_current_language' ) ) {
			$lang = (string) pll_current_language( 'slug' );
		}

		if ( '' === $lang && $post_id > 0 && function_exists( 'apply_filters' ) ) {
			$wpml = apply_filters( 'wpml_post_language_details', null, $post_id );
			if ( is_array( $wpml ) && ! empty( $wpml['language_code'] ) ) {
				$lang = (string) $wpml['language_code'];
			}
		}
		if ( '' === $lang && defined( 'ICL_LANGUAGE_CODE' ) ) {
			$lang = (string) ICL_LANGUAGE_CODE;
		}

		if ( '' === $lang ) {
			$lang = (string) self::get( 'default_language', 'en' );
		}
		if ( '' === $lang ) {
			$lang = substr( (string) get_locale(), 0, 2 );
		}

		return (string) apply_filters( 'cpais_resolve_language', $lang, $post_id );
	}

	public static function update( array $input ) {
		$defaults = self::defaults();
		$existing = get_option( self::OPTION_KEY, array() );
		if ( ! is_array( $existing ) ) {
			$existing = array();
		}

		$clean = array();

		$clean['active_provider'] = in_array( $input['active_provider'] ?? '', self::text_provider_ids(), true )
			? $input['active_provider']
			: $defaults['active_provider'];

		$clean['active_image_provider'] = in_array( $input['active_image_provider'] ?? '', array( 'openai', 'replicate', 'gemini', 'stability' ), true )
			? $input['active_image_provider']
			: $defaults['active_image_provider'];

		$text_fields = array(
			'openai_model',
			'anthropic_model',
			'gemini_model',
			'mistral_model',
			'deepseek_model',
			'grok_model',
			'groq_model',
			'openrouter_model',
			'perplexity_model',
			'default_tone',
			'default_length',
			'default_language',
			'image_openai_model',
			'image_replicate_model',
			'image_gemini_model',
			'image_stability_model',
			'bg_remover_model',
		);
		foreach ( $text_fields as $field ) {
			$clean[ $field ] = sanitize_text_field( $input[ $field ] ?? $defaults[ $field ] );
		}

		$clean['cache_enabled']            = ! empty( $input['cache_enabled'] ) ? 1 : 0;
		$clean['cache_ttl']                = max( 60, min( 7 * DAY_IN_SECONDS, (int) ( $input['cache_ttl'] ?? $defaults['cache_ttl'] ) ) );
		$clean['privacy_consent']          = ! empty( $input['privacy_consent'] ) ? 1 : 0;
		$clean['delete_data_on_uninstall'] = ! empty( $input['delete_data_on_uninstall'] ) ? 1 : 0;
		$clean['faq_schema_enabled']       = ! empty( $input['faq_schema_enabled'] ) ? 1 : 0;
		$clean['faq_default_count']        = max( 1, min( 15, (int) ( $input['faq_default_count'] ?? $defaults['faq_default_count'] ) ) );
		$clean['review_summary_display']   = ! empty( $input['review_summary_display'] ) ? 1 : 0;
		$clean['review_min_count']         = max( 1, min( 50, (int) ( $input['review_min_count'] ?? $defaults['review_min_count'] ) ) );

		foreach ( self::key_fields() as $field ) {
			$clean[ $field ] = self::handle_key_input(
				$input[ $field ] ?? null,
				$existing[ $field ] ?? ''
			);
		}

		update_option( self::OPTION_KEY, $clean, false );
		return true;
	}

	public static function key_fields() {
		return array(
			'openai_api_key',
			'anthropic_api_key',
			'gemini_api_key',
			'mistral_api_key',
			'deepseek_api_key',
			'grok_api_key',
			'groq_api_key',
			'openrouter_api_key',
			'perplexity_api_key',
			'image_openai_api_key',
			'image_replicate_api_key',
			'image_gemini_api_key',
			'image_stability_api_key',
		);
	}

	private static function handle_key_input( $new, $existing_encrypted ) {
		if ( null === $new ) {
			return $existing_encrypted;
		}
		$new = trim( (string) $new );
		if ( '' === $new ) {
			return '';
		}
		return self::encrypt( $new );
	}

	public static function mask_key( $key ) {
		$key = (string) $key;
		$len = strlen( $key );
		if ( $len < 8 ) {
			return '' === $key ? '' : str_repeat( '•', $len );
		}
		return substr( $key, 0, 4 ) . str_repeat( '•', 8 ) . substr( $key, -4 );
	}

	private static function cipher_key() {
		$salt = wp_salt( 'auth' );
		return hash( 'sha256', $salt, true );
	}

	public static function encrypt( $plain ) {
		$plain = (string) $plain;
		if ( '' === $plain ) {
			return '';
		}
		if ( ! function_exists( 'openssl_encrypt' ) ) {
			return base64_encode( $plain ); // phpcs:ignore
		}
		$iv     = openssl_random_pseudo_bytes( 16 );
		$cipher = openssl_encrypt( $plain, 'aes-256-cbc', self::cipher_key(), OPENSSL_RAW_DATA, $iv );
		if ( false === $cipher ) {
			return '';
		}
		return base64_encode( $iv . $cipher ); // phpcs:ignore
	}

	public static function decrypt( $encrypted ) {
		$encrypted = (string) $encrypted;
		if ( '' === $encrypted ) {
			return '';
		}
		$raw = base64_decode( $encrypted, true ); // phpcs:ignore
		if ( false === $raw || strlen( $raw ) < 17 ) {
			return '';
		}
		if ( ! function_exists( 'openssl_decrypt' ) ) {
			return $raw;
		}
		$iv     = substr( $raw, 0, 16 );
		$cipher = substr( $raw, 16 );
		$plain  = openssl_decrypt( $cipher, 'aes-256-cbc', self::cipher_key(), OPENSSL_RAW_DATA, $iv );
		return false === $plain ? '' : $plain;
	}
}
