<?php
/**
 * Settings handler.
 *
 * @package NaveenCodesImageOptimizer
 */

namespace NaveenCodesImageOptimizer;

defined( 'ABSPATH' ) || exit;

/**
 * Registers and sanitizes plugin settings.
 */
class Settings {

	/**
	 * Main settings option.
	 */
	const OPTION_KEY = 'naveencodes_settings';

	/**
	 * Stored analytics.
	 */
	const STATS_OPTION = 'naveencodes_stats';

	/**
	 * Plugin activation timestamp.
	 */
	const ACTIVATED_OPTION = 'naveencodes_activated_at';

	/**
	 * Get default settings.
	 *
	 * @return array
	 */
	public static function get_defaults() {
		return array(
			'server_url'        => defined( 'NAVEENCODES_ENGINE_URL' ) ? NAVEENCODES_ENGINE_URL : '',
			'api_key'           => (string) get_option( Init::API_KEY_OPTION, '' ),
			'async_mode'        => 1,
			'backup_original'   => 1,
			'quality'           => 82,
			'max_width'         => 2560,
			'enable_webp'       => 0,
			'enable_avif'       => 0,
			'strip_metadata'    => 1,
			'smart_compression' => 1,
			'mode'              => 'lossy',
			'timeout'           => 30,
			'retry_attempts'    => 2,
			'batch_size'        => 3,
			'lqip_enabled'      => 1,
		);
	}

	/**
	 * Get default analytics values.
	 *
	 * @return array
	 */
	public static function get_default_stats() {
		return array(
			'total_optimized'      => 0,
			'total_saved_bytes'    => 0,
			'total_original_bytes' => 0,
			'total_output_bytes'   => 0,
			'failed_optimizations' => 0,
		);
	}

	/**
	 * Register admin hooks.
	 */
	public function __construct() {
		add_action( 'admin_init', array( $this, 'register' ) );
	}

	/**
	 * Register settings API fields.
	 *
	 * @return void
	 */
	public function register() {
		register_setting(
			'naveencodes_settings_group',
			self::OPTION_KEY,
			array(
				'type'              => 'array',
				'sanitize_callback' => array( $this, 'sanitize' ),
				'default'           => self::get_defaults(),
			)
		);

		add_settings_section(
			'naveencodes_processing',
			__( 'Batch Processing', 'naveencodes-image-optimizer' ),
			array( $this, 'render_processing_section' ),
			'naveencodes-settings'
		);

		$this->add_number_field(
			'batch_size',
			__( 'Images Per Batch', 'naveencodes-image-optimizer' ),
			1,
			20,
			__( 'Choose how many queued images are processed in one batch run.', 'naveencodes-image-optimizer' ),
			'naveencodes_processing'
		);

		$this->add_checkbox_field(
			'async_mode',
			__( 'Background Optimization', 'naveencodes-image-optimizer' ),
			__( 'Keep uploads non-blocking by sending new images to the queue automatically.', 'naveencodes-image-optimizer' ),
			'naveencodes_processing'
		);

		add_settings_section(
			'naveencodes_profile',
			__( 'Compression Profile', 'naveencodes-image-optimizer' ),
			array( $this, 'render_profile_section' ),
			'naveencodes-settings'
		);

		$this->add_number_field(
			'quality',
			__( 'Image Quality', 'naveencodes-image-optimizer' ),
			40,
			100,
			__( 'Lower values usually create smaller files. Higher values preserve more detail.', 'naveencodes-image-optimizer' ),
			'naveencodes_profile'
		);

		$this->add_number_field(
			'max_width',
			__( 'Maximum Width', 'naveencodes-image-optimizer' ),
			0,
			6000,
			__( 'Resize large images down to this width. Use 0 to keep original dimensions.', 'naveencodes-image-optimizer' ),
			'naveencodes_profile'
		);

		$this->add_select_field(
			'mode',
			__( 'Compression Mode', 'naveencodes-image-optimizer' ),
			array(
				'lossy'    => __( 'Lossy', 'naveencodes-image-optimizer' ),
				'lossless' => __( 'Lossless', 'naveencodes-image-optimizer' ),
			),
			__( 'Lossy typically saves more space. Lossless prioritizes pixel preservation.', 'naveencodes-image-optimizer' ),
			'naveencodes_profile'
		);

		$this->add_checkbox_field(
			'smart_compression',
			__( 'Smart Compression', 'naveencodes-image-optimizer' ),
			__( 'Allow the optimizer to balance visual quality and size automatically.', 'naveencodes-image-optimizer' ),
			'naveencodes_profile'
		);

		$this->add_checkbox_field(
			'strip_metadata',
			__( 'Strip Metadata', 'naveencodes-image-optimizer' ),
			__( 'Remove EXIF and other metadata to reduce output size.', 'naveencodes-image-optimizer' ),
			'naveencodes_profile'
		);

		$this->add_checkbox_field(
			'backup_original',
			__( 'Keep Backup Copy', 'naveencodes-image-optimizer' ),
			__( 'Store a local backup before replacing the original image.', 'naveencodes-image-optimizer' ),
			'naveencodes_profile'
		);

		$this->add_checkbox_field(
			'enable_webp',
			__( 'Generate WebP', 'naveencodes-image-optimizer' ),
			__( 'Create WebP sidecar files when the service returns them.', 'naveencodes-image-optimizer' ),
			'naveencodes_profile'
		);

		$this->add_checkbox_field(
			'enable_avif',
			__( 'Generate AVIF', 'naveencodes-image-optimizer' ),
			__( 'Create AVIF sidecar files when the service returns them.', 'naveencodes-image-optimizer' ),
			'naveencodes_profile'
		);

		add_settings_section(
			'naveencodes_performance',
			__( 'Performance', 'naveencodes-image-optimizer' ),
			array( $this, 'render_performance_section' ),
			'naveencodes-settings'
		);

		$this->add_checkbox_field(
			'lqip_enabled',
			__( 'LQIP Blur Placeholders', 'naveencodes-image-optimizer' ),
			__( 'Show a tiny blurred placeholder instantly while the full image loads — creates a smooth fade-in effect on the front end. Placeholders are generated automatically when images are optimized.', 'naveencodes-image-optimizer' ),
			'naveencodes_performance'
		);

		add_settings_section(
			'naveencodes_reliability',
			__( 'Reliability', 'naveencodes-image-optimizer' ),
			array( $this, 'render_reliability_section' ),
			'naveencodes-settings'
		);

		$this->add_number_field(
			'timeout',
			__( 'Request Timeout', 'naveencodes-image-optimizer' ),
			5,
			120,
			__( 'Maximum number of seconds to wait for a single optimization request.', 'naveencodes-image-optimizer' ),
			'naveencodes_reliability'
		);

		$this->add_number_field(
			'retry_attempts',
			__( 'Retry Attempts', 'naveencodes-image-optimizer' ),
			0,
			5,
			__( 'How many times failed queue items should retry before they are marked as failed.', 'naveencodes-image-optimizer' ),
			'naveencodes_reliability'
		);
	}

	/**
	 * Retrieve all settings merged with defaults.
	 *
	 * @return array
	 */
	public function all() {
		$defaults = self::get_defaults();
		$stored   = get_option( self::OPTION_KEY, array() );
		$settings = wp_parse_args( is_array( $stored ) ? $stored : array(), $defaults );
		$legacy_api_key = '';

		if ( ! empty( $settings['api_key'] ) ) {
			$legacy_api_key = sanitize_text_field( (string) $settings['api_key'] );
		}

		$settings['api_key'] = (string) get_option( Init::API_KEY_OPTION, $legacy_api_key );

		$settings['batch_size']        = min( 20, max( 1, absint( $settings['batch_size'] ) ) );
		$settings['async_mode']        = empty( $settings['async_mode'] ) ? 0 : 1;
		$settings['backup_original']   = empty( $settings['backup_original'] ) ? 0 : 1;
		$settings['quality']           = min( 100, max( 40, absint( $settings['quality'] ) ) );
		$settings['max_width']         = min( 6000, max( 0, absint( $settings['max_width'] ) ) );
		$settings['enable_webp']       = empty( $settings['enable_webp'] ) ? 0 : 1;
		$settings['enable_avif']       = empty( $settings['enable_avif'] ) ? 0 : 1;
		$settings['strip_metadata']    = empty( $settings['strip_metadata'] ) ? 0 : 1;
		$settings['smart_compression'] = empty( $settings['smart_compression'] ) ? 0 : 1;
		$settings['mode']              = in_array( $settings['mode'], array( 'lossy', 'lossless' ), true ) ? $settings['mode'] : 'lossy';
		$settings['timeout']           = min( 120, max( 5, absint( $settings['timeout'] ) ) );
		$settings['retry_attempts']    = min( 5, max( 0, absint( $settings['retry_attempts'] ) ) );
		$settings['lqip_enabled']      = empty( $settings['lqip_enabled'] ) ? 0 : 1;

		return $settings;
	}

	/**
	 * Get one setting value.
	 *
	 * @param string $key Setting name.
	 * @return mixed|null
	 */
	public function get( $key ) {
		$settings = $this->all();

		return array_key_exists( $key, $settings ) ? $settings[ $key ] : null;
	}

	/**
	 * Sanitize user settings.
	 *
	 * @param array $input Raw input.
	 * @return array
	 */
	public function sanitize( $input ) {
		$input    = is_array( $input ) ? $input : array();
		$defaults = self::get_defaults();

		$output = array(
			'batch_size'        => min( 20, max( 1, absint( $input['batch_size'] ?? $defaults['batch_size'] ) ) ),
			'async_mode'        => empty( $input['async_mode'] ) ? 0 : 1,
			'backup_original'   => empty( $input['backup_original'] ) ? 0 : 1,
			'quality'           => min( 100, max( 40, absint( $input['quality'] ?? $defaults['quality'] ) ) ),
			'max_width'         => min( 6000, max( 0, absint( $input['max_width'] ?? $defaults['max_width'] ) ) ),
			'enable_webp'       => empty( $input['enable_webp'] ) ? 0 : 1,
			'enable_avif'       => empty( $input['enable_avif'] ) ? 0 : 1,
			'strip_metadata'    => empty( $input['strip_metadata'] ) ? 0 : 1,
			'smart_compression' => empty( $input['smart_compression'] ) ? 0 : 1,
			'mode'              => in_array( $input['mode'] ?? $defaults['mode'], array( 'lossy', 'lossless' ), true ) ? $input['mode'] : $defaults['mode'],
			'timeout'           => min( 120, max( 5, absint( $input['timeout'] ?? $defaults['timeout'] ) ) ),
			'retry_attempts'    => min( 5, max( 0, absint( $input['retry_attempts'] ?? $defaults['retry_attempts'] ) ) ),
			'lqip_enabled'      => empty( $input['lqip_enabled'] ) ? 0 : 1,
		);

		add_settings_error(
			'naveencodes_messages',
			'naveencodes_saved',
			__( 'NaveenCodes Image Optimizer settings updated.', 'naveencodes-image-optimizer' ),
			'updated'
		);

		return $output;
	}

	/**
	 * Add a checkbox field.
	 *
	 * @param string $key         Setting key.
	 * @param string $label       Field label.
	 * @param string $description Field help.
	 * @param string $section     Settings section ID.
	 * @return void
	 */
	protected function add_checkbox_field( $key, $label, $description, $section ) {
		add_settings_field(
			$key,
			$label,
			function () use ( $key, $description ) {
				$value = (int) $this->get( $key );
				?>
				<label for="naveencodes-<?php echo esc_attr( $key ); ?>" class="naveencodes-field-checkbox">
					<input id="naveencodes-<?php echo esc_attr( $key ); ?>" name="<?php echo esc_attr( self::OPTION_KEY ); ?>[<?php echo esc_attr( $key ); ?>]" type="checkbox" value="1" <?php checked( 1, $value ); ?> />
					<span><?php echo esc_html( $description ); ?></span>
				</label>
				<?php
			},
			'naveencodes-settings',
			$section
		);
	}

	/**
	 * Add a numeric field.
	 *
	 * @param string $key         Setting key.
	 * @param string $label       Field label.
	 * @param int    $min         Min value.
	 * @param int    $max         Max value.
	 * @param string $description Field help.
	 * @param string $section     Settings section ID.
	 * @return void
	 */
	protected function add_number_field( $key, $label, $min, $max, $description, $section ) {
		add_settings_field(
			$key,
			$label,
			function () use ( $key, $min, $max, $description ) {
				$value = (int) $this->get( $key );
				?>
				<input id="naveencodes-<?php echo esc_attr( $key ); ?>" class="small-text" name="<?php echo esc_attr( self::OPTION_KEY ); ?>[<?php echo esc_attr( $key ); ?>]" type="number" min="<?php echo esc_attr( $min ); ?>" max="<?php echo esc_attr( $max ); ?>" value="<?php echo esc_attr( $value ); ?>" />
				<p class="description"><?php echo esc_html( $description ); ?></p>
				<?php
			},
			'naveencodes-settings',
			$section
		);
	}

	/**
	 * Add a select field.
	 *
	 * @param string $key         Setting key.
	 * @param string $label       Field label.
	 * @param array  $options     Allowed options.
	 * @param string $description Field help.
	 * @param string $section     Settings section ID.
	 * @return void
	 */
	protected function add_select_field( $key, $label, $options, $description, $section ) {
		add_settings_field(
			$key,
			$label,
			function () use ( $key, $options, $description ) {
				$value = (string) $this->get( $key );
				?>
				<select id="naveencodes-<?php echo esc_attr( $key ); ?>" name="<?php echo esc_attr( self::OPTION_KEY ); ?>[<?php echo esc_attr( $key ); ?>]">
					<?php foreach ( (array) $options as $option_key => $option_label ) : ?>
						<option value="<?php echo esc_attr( $option_key ); ?>" <?php selected( $value, $option_key ); ?>>
							<?php echo esc_html( $option_label ); ?>
						</option>
					<?php endforeach; ?>
				</select>
				<p class="description"><?php echo esc_html( $description ); ?></p>
				<?php
			},
			'naveencodes-settings',
			$section
		);
	}

	/**
	 * Section intro for processing controls.
	 *
	 * @return void
	 */
	public function render_processing_section() {
		echo '<p>' . esc_html__( 'Control how much work runs in each cycle and whether new uploads are optimized through the queue automatically.', 'naveencodes-image-optimizer' ) . '</p>';
	}

	/**
	 * Section intro for compression controls.
	 *
	 * @return void
	 */
	public function render_profile_section() {
		echo '<p>' . esc_html__( 'Choose the output quality, resize rules, metadata handling, and generated formats for future optimizations.', 'naveencodes-image-optimizer' ) . '</p>';
	}

	/**
	 * Section intro for reliability controls.
	 *
	 * @return void
	 */
	public function render_performance_section() {
		echo '<p>' . esc_html__( 'Front-end loading enhancements that improve perceived performance for visitors.', 'naveencodes-image-optimizer' ) . '</p>';
	}

	public function render_reliability_section() {
		echo '<p>' . esc_html__( 'Tune request timing and retry behavior for slower hosting environments or larger images.', 'naveencodes-image-optimizer' ) . '</p>';
	}
}
