<?php
/**
 * Settings Service
 *
 * Manages plugin settings including API keys, prompts, and configuration options.
 *
 * @package AIPT\Api\Services
 * @since 2.4.1
 */

namespace AIPT\Api\Services;

use AIPT\Api\OpenAI\OpenAIClient;
use AIPT\Api\Gemini\GeminiClient;
use AIPT\Api\OpenRouter\OpenRouterClient;
use AIPT\Api\Claude\ClaudeClient;
use AIPT\Core\Activator;
use AIPT\Utils\ApiKeyManager;

/**
 * Settings Service Implementation
 *
 * Handles all settings-related operations including retrieval, updates, and API key validation.
 *
 * @internal Used by RestEndpoints
 */
class SettingsService {

	/**
	 * Multiline text fields that preserve line breaks
	 *
	 * @var array
	 */
	private const MULTILINE_FIELDS = [
		'advanced_base_prompt',
		'advanced_short_prompt',
		'advanced_full_prompt',
		'standard_description_prompt',
		'title_generation_prompt',
		'faq_generation_prompt',
		'seo_meta_additional_prompt',
		'taxonomy_additional_prompt',
	];

	/**
	 * Valid settings fields
	 *
	 * @var array
	 */
	private $settings_fields;

	/**
	 * Style descriptions
	 *
	 * @var array
	 */
	private $style_descriptions;

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

	/**
	 * Constructor
	 *
	 * @param array $settings_fields Valid settings field names
	 * @param array $style_descriptions Style descriptions mapping
	 * @param AIClientFactoryInterface $ai_client_factory AI client factory instance
	 */
	public function __construct( array $settings_fields, array $style_descriptions, AIClientFactoryInterface $ai_client_factory ) {
		$this->settings_fields    = $settings_fields;
		$this->style_descriptions = $style_descriptions;
		$this->ai_client_factory  = $ai_client_factory;
	}

	/**
	 * Get all settings
	 *
	 * @return array|\WP_Error Settings data or error
	 */
	public function getSettings() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return new \WP_Error( 'rest_forbidden', 'Sorry, you are not allowed to do that.', array( 'status' => 401 ) );
		}

		$settings = array();
		foreach ( $this->settings_fields as $field ) {

			if ( $field === 'openai_api_key' ) {
				$settings[ $field ] = ApiKeyManager::get_api_key_for_display( 'openai' );
				continue;
			}

			if ( $field === 'gemini_api_key' ) {
				$settings[ $field ] = ApiKeyManager::get_api_key_for_display( 'gemini' );
				continue;
			}

			if ( $field === 'openrouter_api_key' ) {
				$settings[ $field ] = ApiKeyManager::get_api_key_for_display( 'openrouter' );
				continue;
			}

			if ( $field === 'claude_api_key' ) {
				$settings[ $field ] = ApiKeyManager::get_api_key_for_display( 'claude' );
				continue;
			}

			$option_value = get_option( 'aipt_' . $field, Activator::get_default_value( $field ) );

			$premium_fields = apply_filters( 'aipt_settings_premium_fields', array() );
			if ( in_array( $field, $premium_fields, true ) ) {
				$can_read = apply_filters( 'aipt_settings_can_read_field', false, $field );
				if ( ! $can_read ) {
					continue;
				}
			}

			if ( $field === 'model' ) {
				$provider_option  = get_option( 'aipt_api_provider', 'openai' );
				$normalized_model = $this->ai_client_factory->normalizeModel( $provider_option, $option_value );
				$settings[ $field ] = sanitize_text_field( $normalized_model );
				continue;
			}

		if ( in_array( $field, self::MULTILINE_FIELDS, true ) ) {
			$settings[ $field ] = wp_kses_post( $option_value );
			continue;
		}

			if ( $field === 'content_length_preset' ) {
				$valid = array( 'short', 'medium', 'long', 'very_long' );
				$settings[ $field ] = in_array( $option_value, $valid, true ) ? $option_value : 'medium';
				continue;
			}

			if ( $field === 'short_length_preset' ) {
				$valid = array( 'brief', 'standard', 'detailed' );
				$settings[ $field ] = in_array( $option_value, $valid, true ) ? $option_value : 'standard';
				continue;
			}

			if ( $field === 'allowed_html_tags' || $field === 'disallowed_html_tags' ) {

				if ( is_string( $option_value ) && ! empty( $option_value ) ) {
					$settings[ $field ] = array_filter( array_map( 'trim', explode( ',', $option_value ) ) );
				} elseif ( is_array( $option_value ) ) {
					$settings[ $field ] = array_map( 'sanitize_text_field', $option_value );
				} else {
					$settings[ $field ] = array();
				}
				continue;
			}

			$settings[ $field ] = sanitize_text_field( $option_value );
		}
		return $settings;
	}

	/**
	 * Update settings
	 *
	 * @param array $request_params Request parameters containing settings to update
	 * @return array|\WP_Error Success response or error
	 */
	public function updateSettings( array $request_params ) {
		try {
			if ( ! current_user_can( 'manage_options' ) ) {
				return new \WP_Error( 'rest_forbidden', 'Sorry, you are not allowed to do that.', array( 'status' => 401 ) );
			}

			$api_provider = isset( $request_params['api_provider'] ) ? sanitize_text_field( $request_params['api_provider'] ) : 'openai';
			$model        = isset( $request_params['model'] ) ? sanitize_text_field( $request_params['model'] ) : '';

			$compatibility_error = $this->validateModelProviderCompatibility( $api_provider, $model );
			if ( is_wp_error( $compatibility_error ) ) {
				return $compatibility_error;
			}

			$api_key_error = $this->processApiKeys( $request_params );
			if ( is_wp_error( $api_key_error ) ) {
				return $api_key_error;
			}

foreach ( $this->settings_fields as $field ) {
				if ( isset( $request_params[ $field ] ) && ! in_array( $field, array( 'openai_api_key', 'gemini_api_key', 'openrouter_api_key', 'claude_api_key' ) ) ) {
					$value = $request_params[ $field ];

					$premium_fields = apply_filters( 'aipt_settings_premium_fields', array() );
					if ( in_array( $field, $premium_fields, true ) ) {
						$can_write = apply_filters( 'aipt_settings_can_write_field', false, $field );
						if ( ! $can_write ) {
							continue;
						}
					}

			if ( in_array( $field, self::MULTILINE_FIELDS, true ) ) {
				$value = $this->sanitizeMultilineText( $value );
			} elseif ( $field === 'allowed_html_tags' || $field === 'disallowed_html_tags' ) {

					if ( is_array( $value ) ) {
						$value = array_map( 'sanitize_text_field', $value );
					} elseif ( is_string( $value ) ) {

						$value = array_filter( array_map( 'trim', explode( ',', $value ) ) );
						$value = array_map( 'sanitize_text_field', $value );
					} else {
						$value = array();
					}
				} else {
					$value = sanitize_text_field( $value );
				}

					if ( $field === 'model' ) {
						$value = $this->ai_client_factory->normalizeModel( $api_provider, $value );
					}

					$validation_error = $this->validateField( $field, $value );
					if ( is_wp_error( $validation_error ) ) {
						return $validation_error;
					}

					update_option( 'aipt_' . $field, $value );
				}
			}

			return array(
				'success' => true,
				'message' => esc_html__( 'Settings updated successfully!', 'ai-product-tools' ),
			);
		} catch ( \Exception $e ) {
			return new \WP_Error( 'update_failed', esc_html($e->getMessage()), array( 'status' => 500 ) );
		} finally {

			try {
				Activator::check_and_update_setup_status();
			} catch ( \Exception $e ) {
			}
		}
	}

	/**
	 * Validate API key
	 *
	 * @param string $api_key API key to validate
	 * @param string $api_provider Provider name (openai|gemini|openrouter)
	 * @return array|\WP_Error Validation result or error
	 */
	public function validateApiKey( string $api_key, string $api_provider = 'openai' ) {

		$api_key = preg_replace( '/\s+/', '', $api_key );

		if ( empty( $api_key ) ) {
			return new \WP_Error(
				'empty_api_key',
				'API key cannot be empty.',
				array(
					'status'        => 400,
					'error_details' => 'API key cannot be empty. Please enter a valid API key.',
				)
			);
		}

		try {
			if ( $api_provider === 'gemini' ) {
				GeminiClient::validate_api_key( $api_key );
			} elseif ( $api_provider === 'openrouter' ) {
				OpenRouterClient::validate_api_key( $api_key );
			} elseif ( $api_provider === 'claude' ) {
				ClaudeClient::validate_api_key( $api_key );
			} else {
				OpenAIClient::validate_api_key( $api_key );
			}

			return array(
				'success' => true,
				'message' => __( 'API key validated successfully', 'ai-product-tools' ),
				'data'    => array(
					'provider'     => $api_provider,
					'validated_at' => current_time( 'mysql' ),
				),
			);
		} catch ( \Exception $e ) {

			return new \WP_Error(
				'validation_error',
				__( 'An error occurred while validating the API key. Please try again.', 'ai-product-tools' ),
				array(
					'status' => 400,
					'error_details' => sanitize_text_field( $e->getMessage() ),
				)
			);
		}
	}

	/**
	 * Sanitize API key
	 *
	 * @param string $key API key to sanitize
	 * @return string Sanitized key
	 */
	public function sanitizeApiKey( string $key ): string {
		$key = trim( $key );
		$key = preg_replace( '/\s+/', '', $key );
		return sanitize_text_field( $key );
	}

	/**
	 * Sanitize multiline text
	 *
	 * @param string $text Text to sanitize
	 * @return string Sanitized text
	 */
	private function sanitizeMultilineText( string $text ): string {
		$text = wp_strip_all_tags( $text, false );
		$text = preg_replace( '/\r\n|\r/', "\n", $text );

		$lines           = explode( "\n", $text );
		$sanitized_lines = array();

		foreach ( $lines as $line ) {
			$line = trim( $line );
			if ( strlen( $line ) > 0 ) {
				$line = preg_replace( '/[<>"\'()]/', '', $line );
				$line = sanitize_text_field( $line );
			}
			$sanitized_lines[] = $line;
		}

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

	/**
	 * Validate model/provider compatibility
	 *
	 * @param string $api_provider Provider name
	 * @param string $model Model identifier
	 * @return true|\WP_Error True if valid, WP_Error if invalid
	 */
	private function validateModelProviderCompatibility( string $api_provider, string $model ) {
		if ( $api_provider === 'openai' && strpos( $model, 'gemini-' ) === 0 ) {
			return new \WP_Error(
				'invalid_model',
				esc_html__( 'OpenAI API provider cannot be used with Gemini models.', 'ai-product-tools' ),
				array( 'status' => 400 )
			);
		}

		if ( $api_provider === 'gemini' && strpos( $model, 'gemini-' ) !== 0 ) {
			return new \WP_Error(
				'invalid_model',
				esc_html__( 'Gemini API provider cannot be used with non-Gemini models.', 'ai-product-tools' ),
				array( 'status' => 400 )
			);
		}

		if ( $api_provider === 'openrouter' && ( strpos( $model, 'gemini-' ) === 0 || strpos( $model, 'gpt-' ) === 0 ) ) {
			return new \WP_Error(
				'invalid_model',
				esc_html__( 'OpenRouter API provider cannot be used with OpenAI or Gemini direct models.', 'ai-product-tools' ),
				array( 'status' => 400 )
			);
		}

		if ( $api_provider === 'claude' && strpos( $model, 'claude-' ) !== 0 ) {
			return new \WP_Error(
				'invalid_model',
				esc_html__( 'Claude API provider cannot be used with non-Claude models.', 'ai-product-tools' ),
				array( 'status' => 400 )
			);
		}

		return true;
	}

	/**
	 * Process API key updates
	 *
	 * @param array $request_params Request parameters
	 * @return true|\WP_Error True if successful, WP_Error on failure
	 */
	private function processApiKeys( array $request_params ) {

		$openai_provided = array_key_exists( 'openai_api_key', $request_params );
		$api_key = (array_key_exists( 'openai_api_key', $request_params ) && is_string( $request_params['openai_api_key'] )) ? $this->sanitizeApiKey( $request_params['openai_api_key'] ) : null;
		$result = $this->processProviderKey(
			$api_key,
			[ OpenAIClient::class, 'validate_api_key' ],
			[ ApiKeyManager::class, 'get_openai_key' ],
			[ ApiKeyManager::class, 'set_openai_key' ],
			'OpenAI'
		);
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		$gemini_provided = array_key_exists( 'gemini_api_key', $request_params );
		$gemini_api_key = (array_key_exists( 'gemini_api_key', $request_params ) && is_string( $request_params['gemini_api_key'] )) ? $this->sanitizeApiKey( $request_params['gemini_api_key'] ) : null;
		$result = $this->processProviderKey(
			$gemini_api_key,
			[ GeminiClient::class, 'validate_api_key' ],
			[ ApiKeyManager::class, 'get_gemini_key' ],
			[ ApiKeyManager::class, 'set_gemini_key' ],
			'Gemini'
		);
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		$openrouter_provided = array_key_exists( 'openrouter_api_key', $request_params );
		$openrouter_api_key = (array_key_exists( 'openrouter_api_key', $request_params ) && is_string( $request_params['openrouter_api_key'] )) ? $this->sanitizeApiKey( $request_params['openrouter_api_key'] ) : null;
		$result = $this->processProviderKey(
			$openrouter_api_key,
			[ OpenRouterClient::class, 'validate_api_key' ],
			[ ApiKeyManager::class, 'get_openrouter_key' ],
			[ ApiKeyManager::class, 'set_openrouter_key' ],
			'OpenRouter'
		);
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		$claude_api_key = (array_key_exists( 'claude_api_key', $request_params ) && is_string( $request_params['claude_api_key'] )) ? $this->sanitizeApiKey( $request_params['claude_api_key'] ) : null;
		$result = $this->processProviderKey(
			$claude_api_key,
			[ ClaudeClient::class, 'validate_api_key' ],
			[ ApiKeyManager::class, 'get_claude_key' ],
			[ ApiKeyManager::class, 'set_claude_key' ],
			'Claude'
		);
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		return true;
	}

	/**
	 * Process a single provider API key
	 *
	 * @param string|null $api_key API key value (null = param not provided, '' = explicitly clear)
	 * @param callable $validator Validation function
	 * @param callable $getter Function to get current key
	 * @param callable $setter Function to set key
	 * @param string $provider_label Provider display name
	 * @return true|\WP_Error True if successful, WP_Error on failure
	 */
	private function processProviderKey( ?string $api_key, callable $validator, callable $getter, callable $setter, string $provider_label ) {

		if ( $api_key === null ) {
			return true;
		}

		$current_key = call_user_func( $getter );

		if ( $api_key === '' ) {
			if ( ! empty( $current_key ) ) {
				if ( ! call_user_func( $setter, '' ) ) {
					return new \WP_Error(
						'api_key_save_failed',
						sprintf(
							/* translators: %s: Provider name (e.g., OpenAI, Gemini) */
							__( 'Failed to save %s API key. Please try again.', 'ai-product-tools' ),
							$provider_label
						),
						array( 'status' => 500 )
					);
				}
			}
			return true;
		}

		if ( $api_key === $current_key ) {
			return true;
		}

		try {
			call_user_func( $validator, $api_key );
		} catch ( \Exception $e ) {
			return new \WP_Error(
				'invalid_api_key',
				sprintf(
					/* translators: %s: Provider name (e.g., OpenAI, Gemini) */
					__( 'Invalid %s API key', 'ai-product-tools' ),
					$provider_label
				),
				array( 'status' => 400 )
			);
		}

		if ( ! call_user_func( $setter, $api_key ) ) {
			return new \WP_Error(
				'api_key_save_failed',
				sprintf(
					/* translators: %s: Provider name (e.g., OpenAI, Gemini) */
					__( 'Failed to save %s API key. Please try again.', 'ai-product-tools' ),
					$provider_label
				),
				array( 'status' => 500 )
			);
		}

		return true;
	}

	/**
	 * Validate individual field value
	 *
	 * @param string $field Field name
	 * @param mixed $value Field value
	 * @return true|\WP_Error True if valid, WP_Error if invalid
	 */
	private function validateField( string $field, $value ) {
		switch ( $field ) {
			case 'content_length_preset':
				$valid_presets = array( 'short', 'medium', 'long', 'very_long' );
				if ( ! in_array( $value, $valid_presets, true ) ) {
					return new \WP_Error(
						'invalid_content_length_preset',
						'Invalid content length preset',
						array( 'status' => 400 )
					);
				}
				break;
			case 'short_length_preset':
				$valid_presets = array( 'brief', 'standard', 'detailed' );
				if ( ! in_array( $value, $valid_presets, true ) ) {
					return new \WP_Error(
						'invalid_short_length_preset',
						'Invalid short description length preset',
						array( 'status' => 400 )
					);
				}
				break;
			case 'max_tags_count':
				if ( ! is_numeric( $value ) || intval( $value ) < 1 || intval( $value ) > 20 ) {
					return new \WP_Error(
						'invalid_max_tags_count',
						'Maximum tag count must be a positive number between 1 and 20',
						array( 'status' => 400 )
					);
				}
				break;
			case 'language':
				$valid_languages = array( 'Afrikaans', 'Arabic', 'Bulgarian', 'Bengali', 'Czech', 'Danish', 'German', 'Greek', 'English', 'English (UK)', 'Spanish', 'Estonian', 'Persian', 'Finnish', 'French', 'Hebrew', 'Hindi', 'Croatian', 'Hungarian', 'Indonesian', 'Italian', 'Japanese', 'Korean', 'Lithuanian', 'Latvian', 'Malay', 'Dutch', 'Norwegian', 'Polish', 'Portuguese', 'Romanian', 'Russian', 'Serbian', 'Slovak', 'Slovenian', 'Swedish', 'Thai', 'Turkish', 'Ukrainian', 'Urdu', 'Vietnamese', 'Chinese' );
				if ( ! in_array( $value, $valid_languages ) ) {
					return new \WP_Error( 'invalid_language', 'Invalid language selection', array( 'status' => 400 ) );
				}
				break;
			case 'writing_style':
				if ( ! array_key_exists( $value, $this->style_descriptions ) ) {
					return new \WP_Error( 'invalid_style', 'Invalid writing style selection', array( 'status' => 400 ) );
				}
				break;
		case 'api_provider':
				if ( ! in_array( $value, array( 'openai', 'gemini', 'openrouter', 'claude' ) ) ) {
					return new \WP_Error( 'invalid_provider', 'Invalid API provider selection', array( 'status' => 400 ) );
				}
				break;
		}

		return true;
	}
}
