<?php
/**
 * Settings registration, defaults, and sanitisation.
 *
 * @package AetherisAIChat
 */

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

final class Aetheris_AI_Chat_Settings {

	const OPTION_GROUP = 'aetheris_ai_chat_group';

	public static function init() {
		add_action( 'admin_init', array( __CLASS__, 'register' ) );
		add_action( 'update_option_' . AETHERIS_AI_CHAT_OPTION, array( __CLASS__, 'flush_cache' ) );
	}

	public static function flush_cache() {
		global $wpdb;
		// Best-effort: blast every transient we may have cached. There is no
		// core API for "delete all transients matching a prefix", so a direct
		// query against $wpdb->options is the standard pattern. Object-cache
		// hits are cleared with wp_cache_flush_group() right after.
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wpdb->query(
			"DELETE FROM {$wpdb->options} WHERE option_name LIKE '\_transient\_aetheris\_%' OR option_name LIKE '\_transient\_timeout\_aetheris\_%'"
		);

		if ( function_exists( 'wp_cache_flush_group' ) ) {
			wp_cache_flush_group( 'transient' );
		}
	}

	public static function defaults() {
		return array(
			'public_key'   => '',
			'api_key'      => '',
			'enabled'      => 1,
			'white_label'  => 0,
			'position'     => 'bottom-right',
			'load_on'      => 'all',
			'api_base'     => AETHERIS_AI_CHAT_DEFAULT_API,
			'widget_src'   => AETHERIS_AI_CHAT_DEFAULT_WIDGET,
		);
	}

	public static function get( $key = null ) {
		$saved   = get_option( AETHERIS_AI_CHAT_OPTION, array() );
		$merged  = wp_parse_args( is_array( $saved ) ? $saved : array(), self::defaults() );
		if ( null === $key ) {
			return $merged;
		}
		return isset( $merged[ $key ] ) ? $merged[ $key ] : null;
	}

	public static function register() {
		register_setting(
			self::OPTION_GROUP,
			AETHERIS_AI_CHAT_OPTION,
			array(
				'type'              => 'array',
				'sanitize_callback' => array( __CLASS__, 'sanitize' ),
				'default'           => self::defaults(),
			)
		);
	}

	/**
	 * Sanitise + validate every field. Untrusted user input arrives here.
	 */
	public static function sanitize( $input ) {
		$current  = self::get();
		$clean    = $current;

		if ( ! is_array( $input ) ) {
			return $clean;
		}

		if ( isset( $input['public_key'] ) ) {
			$pk = sanitize_text_field( wp_unslash( $input['public_key'] ) );
			if ( '' === $pk || preg_match( '/^[A-Za-z0-9_\-]{8,128}$/', $pk ) ) {
				$clean['public_key'] = $pk;
			} else {
				add_settings_error(
					AETHERIS_AI_CHAT_OPTION,
					'invalid_public_key',
					__( 'Public key contains invalid characters.', 'aetheris-ai-chat' )
				);
			}
		}

		if ( isset( $input['api_key'] ) ) {
			$ak = sanitize_text_field( wp_unslash( $input['api_key'] ) );
			if ( '' === $ak || preg_match( '/^[A-Za-z0-9_\-\.]{8,256}$/', $ak ) ) {
				$clean['api_key'] = $ak;
			}
		}

		$clean['enabled']     = ! empty( $input['enabled'] ) ? 1 : 0;
		$clean['white_label'] = ! empty( $input['white_label'] ) ? 1 : 0;

		$allowed_positions = array( 'bottom-right', 'bottom-left' );
		if ( isset( $input['position'] ) && in_array( $input['position'], $allowed_positions, true ) ) {
			$clean['position'] = $input['position'];
		}

		$allowed_load = array( 'all', 'front_only', 'no_admin' );
		if ( isset( $input['load_on'] ) && in_array( $input['load_on'], $allowed_load, true ) ) {
			$clean['load_on'] = $input['load_on'];
		}

		if ( isset( $input['api_base'] ) ) {
			$url = esc_url_raw( trim( wp_unslash( $input['api_base'] ) ) );
			if ( '' !== $url ) {
				$clean['api_base'] = $url;
			}
		}

		if ( isset( $input['widget_src'] ) ) {
			$url = esc_url_raw( trim( wp_unslash( $input['widget_src'] ) ) );
			if ( '' !== $url ) {
				$clean['widget_src'] = $url;
			}
		}

		return $clean;
	}
}
