<?php
/**
 * Author: Rymera Web Co.
 *
 * @package SAAI\REST\Chat
 */

namespace SAAI\REST\Chat;

use SAAI\Abstracts\Abstract_REST;
use SAAI\Traits\Singleton_Trait;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

defined( 'ABSPATH' ) || exit;

/**
 * Chat_Widget_Settings REST API controller class.
 *
 * @since 1.0.8
 */
class Chat_Widget_Settings extends Abstract_REST {

    use Singleton_Trait;

    /**
     * Holds the class instance object
     *
     * @since 1.0.8
     * @var Chat_Widget_Settings $instance object
     */
    protected static $instance;

    /**
     * WordPress option key for storing chat widget settings.
     *
     * @since 1.0.8
     */
    const OPTION_KEY = 'saai_chat_widget_settings';

    /**
     * REST constructor.
     *
     * @since 1.0.8
     */
    public function __construct() {
    }

    /**
     * Works as constructor for this class.
     *
     * @since 1.0.8
     * @return void
     */
    public function register_plugin_routes() {
        $this->rest_base = 'chat-widget-settings';
        parent::register_plugin_routes();
    }

    /**
     * Register the routes for Chat Widget Settings.
     *
     * @since 1.0.8
     * @return void
     */
    public function register_routes() {
        // Get settings endpoint.
        register_rest_route(
            $this->namespace,
            "/$this->rest_base",
            array(
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => array( $this, 'get_settings' ),
                'permission_callback' => array( $this, 'get_item_permissions_check' ),
            )
        );

        // Search coupons endpoint for admin UI.
        register_rest_route(
            $this->namespace,
            "/$this->rest_base/coupons",
            array(
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => array( $this, 'search_coupons' ),
                'permission_callback' => array( $this, 'get_item_permissions_check' ),
                'args'                => array(
                    'search' => array(
                        'required'          => false,
                        'type'              => 'string',
                        'default'           => '',
                        'description'       => __( 'Search coupons by code.', 'storeagent-ai-for-woocommerce' ),
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                ),
            )
        );

        // Save settings endpoint.
        register_rest_route(
            $this->namespace,
            "/$this->rest_base",
            array(
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => array( $this, 'save_settings' ),
                'permission_callback' => array( $this, 'update_item_permissions_check' ),
                'args'                => array(
                    'settings' => array(
                        'required'          => true,
                        'validate_callback' => array( $this, 'validate_settings' ),
                        'sanitize_callback' => array( $this, 'sanitize_settings' ),
                    ),
                ),
            )
        );
    }

    /**
     * Get chat widget settings.
     *
     * @since 1.0.8
     * @since 1.1.4 Added excluded_pages_details to response containing resolved page titles.
     *
     * @param WP_REST_Request $request The request object.
     * @return WP_REST_Response The response object.
     */
    public function get_settings( $request ) {
        $settings       = self::get_default_settings();
        $saved_settings = get_option( self::OPTION_KEY, array() );

        // Merge saved settings with defaults.
        $settings = wp_parse_args( $saved_settings, $settings );

        // Resolve page titles for excluded pages.
        $excluded_pages_details = array();
        if ( ! empty( $settings['excluded_pages'] ) ) {
            foreach ( $settings['excluded_pages'] as $page_id ) {
                $page_title               = get_the_title( absint( $page_id ) );
                $excluded_pages_details[] = array(
                    'id'    => (int) $page_id,
                    'title' => $page_title ? $page_title : '',
                );
            }
        }
        $settings['excluded_pages_details'] = $excluded_pages_details;

        // Resolve coupon details for offering coupon IDs.
        $offering_coupon_details = array();
        if ( ! empty( $settings['offering_coupon_ids'] ) ) {
            $coupon_posts = get_posts(
                array(
                    'post_type'   => 'shop_coupon',
                    'post__in'    => array_map( 'absint', $settings['offering_coupon_ids'] ),
                    'numberposts' => -1,
                )
            );

            foreach ( $coupon_posts as $coupon_post ) {
                $coupon                   = new \WC_Coupon( $coupon_post->ID );
                $offering_coupon_details[] = array(
                    'id'          => $coupon->get_id(),
                    'code'        => $coupon->get_code(),
                    'description' => $coupon->get_description(),
                );
            }
        }
        $settings['offering_coupon_details'] = $offering_coupon_details;

        return $this->rest_response( $settings, $request );
    }

    /**
     * Save chat widget settings.
     *
     * @param WP_REST_Request $request The request object.
     * @return WP_REST_Response|WP_Error The response object or error.
     */
    public function save_settings( $request ) {
        $settings = $request->get_param( 'settings' );

        // Save settings to WordPress options.
        update_option( self::OPTION_KEY, $settings );

        return $this->rest_response(
            array(
                'settings' => $settings,
                'message'  => __( 'Chat widget settings saved successfully.', 'storeagent-ai-for-woocommerce' ),
            ),
            $request
        );
    }

    /**
     * Search coupons for the admin coupon selector.
     *
     * @since 1.3.0
     * @param WP_REST_Request $request The request object.
     * @return WP_REST_Response The response object.
     */
    public function search_coupons( $request ) {
        $search = $request->get_param( 'search' );

        // Require at least 2 characters to search.
        if ( empty( $search ) || strlen( $search ) < 2 ) {
            return $this->rest_response( array(), $request );
        }

        $args = array(
            'posts_per_page' => 25,
            'post_type'      => 'shop_coupon',
            'post_status'    => 'publish',
            'orderby'        => 'title',
            'order'          => 'ASC',
        );

        $args['s'] = $search;

        $coupon_posts = get_posts( $args );
        $coupons      = array();

        foreach ( $coupon_posts as $post ) {
            $coupon    = new \WC_Coupon( $post->ID );
            $coupons[] = array(
                'id'          => $post->ID,
                'code'        => $coupon->get_code(),
                'description' => $coupon->get_description(),
                'type'        => $coupon->get_discount_type(),
                'amount'      => $coupon->get_amount(),
            );
        }

        return $this->rest_response( $coupons, $request );
    }

    /**
     * Checks if a given request has access to read items.
     *
     * Overrides the parent method to require `manage_woocommerce` capability
     * since chat widget settings and coupon data are admin-only.
     *
     * @since 1.3.0
     * @param WP_REST_Request $request Full data about the request.
     * @return bool True if the request has read access, false otherwise.
     */
    public function get_item_permissions_check( $request ) {
        return current_user_can( 'manage_woocommerce' );
    }

    /**
     * Get default chat widget settings.
     *
     * @return array Default settings.
     */
    public static function get_default_settings() {
        return array(
            // General settings.
            'enabled'                      => true,

            // Brand colors.
            'brand_primary'                => '#ffcc28',
            'brand_secondary'              => '#f0b800',

            // Layout & containers.
            'container_bg'                 => '#ffffff',
            'header_bg'                    => '#ffffff',
            'input_bg'                     => '#ffffff',

            // Interactive elements.
            'trigger_bg'                   => '#ffcc28',
            'trigger_hover_bg'             => '#f0b800',
            'chat_icon_color'              => '#000000',
            'send_button_bg'               => '#1890ff',
            'send_button_hover_bg'         => '#40a9ff',
            'online_indicator_bg'          => '#52c41a',

            // Messages.
            'user_message_bg'              => '#1890ff',
            'ai_message_bg'                => '#ffffff',

            // Typography.
            'text_primary'                 => '#333333',
            'text_secondary'               => '#666666',

            // Input fields.
            'input_border'                 => '#e8e8e8',
            'input_focus_border'           => '#1890ff',

            // Error states.
            'error_bg'                     => '#fef2f2',
            'error_text'                   => '#dc2626',

            // Other settings.
            'position'                     => 'bottom-right',
            'position_tablet'              => 'bottom-right',
            'position_mobile'              => 'bottom-right',
            'open_by_default'              => false,
            'open_by_default_tablet'       => false,
            'open_by_default_mobile'       => false,
            'greeting'                     => __( "👋 Hi there! I'm your real-time smart AI assistant. Ask me anything about our products. How can I help today?", 'storeagent-ai-for-woocommerce' ),
            'placeholder'                  => __( 'Type your message...', 'storeagent-ai-for-woocommerce' ),
            'assistant_name'               => __( 'AI Assistant', 'storeagent-ai-for-woocommerce' ),
            'avatar_acronym'               => __( 'AI', 'storeagent-ai-for-woocommerce' ),
            'status_text'                  => __( 'Online', 'storeagent-ai-for-woocommerce' ),
            'tones'                        => array(),

            // Display settings.
            'display_post_types'           => array( 'product' ),
            'display_my_account'           => false,
            'excluded_pages'               => self::get_default_excluded_pages(),

            // Coupon offering settings.
            'allow_coupon_offering'        => false,
            'offering_coupon_ids'          => array(),
            'offering_coupon_instructions' => array(),
        );
    }

    /**
     * Get default excluded pages (includes WooCommerce Cart and Checkout pages).
     *
     * @return array Array of page IDs to exclude by default.
     */
    private static function get_default_excluded_pages() {
        $excluded_pages = array();

        // Add WooCommerce Cart and Checkout page IDs if WooCommerce is active.
        if ( function_exists( 'wc_get_page_id' ) ) {
            $cart_page_id = wc_get_page_id( 'cart' );
            if ( $cart_page_id > 0 ) {
                $excluded_pages[] = $cart_page_id;
            }

            $checkout_page_id = wc_get_page_id( 'checkout' );
            if ( $checkout_page_id > 0 ) {
                $excluded_pages[] = $checkout_page_id;
            }
        }

        return $excluded_pages;
    }

    /**
     * Validate chat widget settings.
     *
     * @param array $settings The settings array to validate.
     * @return bool True if valid, false otherwise.
     */
    public function validate_settings( $settings ) {
        if ( ! is_array( $settings ) ) {
            return false;
        }

        $defaults = self::get_default_settings();

        // Check for required fields.
        $required_fields = array(
            'brand_primary',
            'position',
            'greeting',
            'placeholder',
            'assistant_name',
            'avatar_acronym',
            'status_text',
        );

        foreach ( $required_fields as $field ) {
            if ( ! isset( $settings[ $field ] ) || empty( $settings[ $field ] ) ) {
                return false;
            }
        }

        // Validate enabled field (should be boolean).
        if ( isset( $settings['enabled'] ) && ! is_bool( $settings['enabled'] ) ) {
            return false;
        }

        // Validate open_by_default fields (should be boolean).
        $open_by_default_fields = array( 'open_by_default', 'open_by_default_tablet', 'open_by_default_mobile' );
        foreach ( $open_by_default_fields as $field ) {
            if ( isset( $settings[ $field ] ) && ! is_bool( $settings[ $field ] ) ) {
                return false;
            }
        }

        // Validate position.
        $valid_positions = array( 'bottom-right', 'bottom-left', 'top-right', 'top-left' );
        if ( ! in_array( $settings['position'], $valid_positions, true ) ) {
            return false;
        }

        // Validate device-specific positions (optional fields).
        $device_positions = array( 'position_tablet', 'position_mobile' );
        foreach ( $device_positions as $device_position ) {
            if ( isset( $settings[ $device_position ] ) && ! empty( $settings[ $device_position ] ) ) {
                if ( ! in_array( $settings[ $device_position ], $valid_positions, true ) ) {
                    return false;
                }
            }
        }

        // Validate tones.
        if ( isset( $settings['tones'] ) ) {
            if ( ! is_array( $settings['tones'] ) ) {
                return false;
            }

            // Maximum 3 tones allowed.
            if ( count( $settings['tones'] ) > 3 ) {
                return false;
            }

            // Validate against available tones.
            $available_tones = self::get_available_tones();
            foreach ( $settings['tones'] as $tone ) {
                if ( ! array_key_exists( $tone, $available_tones ) ) {
                    return false;
                }
            }
        }

        // Validate colors (hex format).
        $color_fields = array(
            'brand_primary',
            'brand_secondary',
            'container_bg',
            'header_bg',
            'input_bg',
            'trigger_bg',
            'trigger_hover_bg',
            'chat_icon_color',
            'send_button_bg',
            'send_button_hover_bg',
            'online_indicator_bg',
            'user_message_bg',
            'ai_message_bg',
            'text_primary',
            'text_secondary',
            'input_border',
            'input_focus_border',
            'error_bg',
            'error_text',
        );
        foreach ( $color_fields as $field ) {
            if ( isset( $settings[ $field ] ) && ! empty( $settings[ $field ] ) ) {
                if ( ! preg_match( '/^#([a-fA-F0-9]{3}|[a-fA-F0-9]{6})$/', $settings[ $field ] ) ) {
                    return false;
                }
            }
        }

        // Validate display_post_types (should be array of strings).
        if ( isset( $settings['display_post_types'] ) ) {
            if ( ! is_array( $settings['display_post_types'] ) ) {
                return false;
            }
            foreach ( $settings['display_post_types'] as $post_type ) {
                if ( ! is_string( $post_type ) ) {
                    return false;
                }
            }
        }

        // Validate display_my_account (should be boolean).
        if ( isset( $settings['display_my_account'] ) && ! is_bool( $settings['display_my_account'] ) ) {
            return false;
        }

        // Validate allow_coupon_offering (should be boolean).
        if ( isset( $settings['allow_coupon_offering'] ) && ! is_bool( $settings['allow_coupon_offering'] ) ) {
            return false;
        }

        // Validate offering_coupon_ids (should be array of integers or numeric strings).
        if ( isset( $settings['offering_coupon_ids'] ) ) {
            if ( ! is_array( $settings['offering_coupon_ids'] ) ) {
                return false;
            }
            foreach ( $settings['offering_coupon_ids'] as $coupon_id ) {
                if ( ! is_int( $coupon_id ) && ! is_numeric( $coupon_id ) ) {
                    return false;
                }
            }
        }

        // Validate offering_coupon_instructions (should be associative array of strings).
        if ( isset( $settings['offering_coupon_instructions'] ) ) {
            if ( ! is_array( $settings['offering_coupon_instructions'] ) ) {
                return false;
            }
            foreach ( $settings['offering_coupon_instructions'] as $coupon_id => $instruction ) {
                if ( ! is_numeric( $coupon_id ) || ! is_string( $instruction ) ) {
                    return false;
                }
            }
        }

        // Validate excluded_pages (should be array of integers or numeric strings).
        if ( isset( $settings['excluded_pages'] ) ) {
            if ( ! is_array( $settings['excluded_pages'] ) ) {
                return false;
            }
            foreach ( $settings['excluded_pages'] as $page_id ) {
                // Accept integers or numeric strings.
                if ( ! is_int( $page_id ) && ! is_numeric( $page_id ) ) {
                    return false;
                }
            }
        }

        return true;
    }

    /**
     * Sanitize chat widget settings.
     *
     * @param array $settings The settings array to sanitize.
     * @return array Sanitized settings.
     */
    public function sanitize_settings( $settings ) {
        $sanitized = $settings; // Start with original settings to preserve all fields.
        $defaults  = self::get_default_settings();

        // Sanitize enabled field.
        if ( isset( $settings['enabled'] ) ) {
            $sanitized['enabled'] = (bool) $settings['enabled'];
        }

        // Sanitize open_by_default fields.
        $open_by_default_fields = array( 'open_by_default', 'open_by_default_tablet', 'open_by_default_mobile' );
        foreach ( $open_by_default_fields as $field ) {
            if ( isset( $settings[ $field ] ) ) {
                $sanitized[ $field ] = (bool) $settings[ $field ];
            }
        }

        // Sanitize text fields.
        $text_fields = array( 'greeting', 'placeholder', 'assistant_name', 'avatar_acronym', 'status_text' );
        foreach ( $text_fields as $field ) {
            if ( isset( $settings[ $field ] ) ) {
                $sanitized[ $field ] = sanitize_text_field( $settings[ $field ] );
            }
        }

        // Sanitize colors.
        $color_fields = array(
            'brand_primary',
            'brand_secondary',
            'container_bg',
            'header_bg',
            'input_bg',
            'trigger_bg',
            'trigger_hover_bg',
            'chat_icon_color',
            'send_button_bg',
            'send_button_hover_bg',
            'online_indicator_bg',
            'user_message_bg',
            'ai_message_bg',
            'text_primary',
            'text_secondary',
            'input_border',
            'input_focus_border',
            'error_bg',
            'error_text',
        );
        foreach ( $color_fields as $field ) {
            if ( isset( $settings[ $field ] ) ) {
                $sanitized[ $field ] = sanitize_hex_color( $settings[ $field ] );
            }
        }

        // Sanitize position.
        if ( isset( $settings['position'] ) ) {
            $valid_positions       = array( 'bottom-right', 'bottom-left', 'top-right', 'top-left' );
            $sanitized['position'] = in_array( $settings['position'], $valid_positions, true )
                ? $settings['position']
                : $defaults['position'];
        }

        // Sanitize device-specific positions.
        $device_positions = array( 'position_tablet', 'position_mobile' );
        foreach ( $device_positions as $device_position ) {
            if ( isset( $settings[ $device_position ] ) ) {
                $valid_positions               = array( 'bottom-right', 'bottom-left', 'top-right', 'top-left' );
                $sanitized[ $device_position ] = in_array( $settings[ $device_position ], $valid_positions, true )
                    ? $settings[ $device_position ]
                    : $defaults[ $device_position ];
            }
        }

        // Sanitize tones.
        if ( isset( $settings['tones'] ) && is_array( $settings['tones'] ) ) {
            $available_tones = self::get_available_tones();
            $sanitized_tones = array();

            // Limit to maximum 3 tones and validate each one.
            foreach ( array_slice( $settings['tones'], 0, 3 ) as $tone ) {
                $tone = sanitize_text_field( $tone );
                if ( array_key_exists( $tone, $available_tones ) ) {
                    $sanitized_tones[] = $tone;
                }
            }

            $sanitized['tones'] = $sanitized_tones;
        }

        // Sanitize display_post_types.
        if ( isset( $settings['display_post_types'] ) && is_array( $settings['display_post_types'] ) ) {
            $sanitized_post_types = array();
            foreach ( $settings['display_post_types'] as $post_type ) {
                $sanitized_post_type = sanitize_key( $post_type );
                if ( ! empty( $sanitized_post_type ) ) {
                    $sanitized_post_types[] = $sanitized_post_type;
                }
            }
            $sanitized['display_post_types'] = array_unique( $sanitized_post_types );
        }

        // Sanitize display_my_account.
        if ( isset( $settings['display_my_account'] ) ) {
            $sanitized['display_my_account'] = (bool) $settings['display_my_account'];
        }

        // Sanitize allow_coupon_offering.
        if ( isset( $settings['allow_coupon_offering'] ) ) {
            $sanitized['allow_coupon_offering'] = (bool) $settings['allow_coupon_offering'];
        }

        // Sanitize offering_coupon_ids.
        if ( isset( $settings['offering_coupon_ids'] ) && is_array( $settings['offering_coupon_ids'] ) ) {
            $sanitized_coupon_ids = array();
            foreach ( $settings['offering_coupon_ids'] as $coupon_id ) {
                $sanitized_coupon_id = absint( $coupon_id );
                if ( $sanitized_coupon_id > 0 ) {
                    $sanitized_coupon_ids[] = $sanitized_coupon_id;
                }
            }
            $sanitized['offering_coupon_ids'] = array_unique( $sanitized_coupon_ids );
        }

        // Sanitize offering_coupon_instructions.
        if ( isset( $settings['offering_coupon_instructions'] ) && is_array( $settings['offering_coupon_instructions'] ) ) {
            $sanitized_instructions = array();
            foreach ( $settings['offering_coupon_instructions'] as $coupon_id => $instruction ) {
                $sanitized_coupon_id = absint( $coupon_id );
                if ( $sanitized_coupon_id > 0 ) {
                    // Limit instruction length to 200 characters.
                    $sanitized_instructions[ (string) $sanitized_coupon_id ] = sanitize_text_field( substr( $instruction, 0, 200 ) );
                }
            }
            $sanitized['offering_coupon_instructions'] = $sanitized_instructions;
        }

        // Sanitize excluded_pages.
        if ( isset( $settings['excluded_pages'] ) && is_array( $settings['excluded_pages'] ) ) {
            $sanitized_excluded_pages = array();
            foreach ( $settings['excluded_pages'] as $page_id ) {
                $sanitized_page_id = absint( $page_id );
                if ( $sanitized_page_id > 0 ) {
                    $sanitized_excluded_pages[] = $sanitized_page_id;
                }
            }
            $sanitized['excluded_pages'] = array_unique( $sanitized_excluded_pages );
        }

        return $sanitized;
    }

    /**
     * Get available tones from options-tones.php.
     *
     * @return array Available tones.
     */
    public static function get_available_tones() {
        $tones_file = SAAI_PLUGIN_DIR_PATH . 'data/options-tones.php';
        if ( file_exists( $tones_file ) ) {
            return include $tones_file;
        }

        // Fallback tones if file doesn't exist.
        return array(
            'friendly'     => __( 'Friendly', 'storeagent-ai-for-woocommerce' ),
            'professional' => __( 'Professional', 'storeagent-ai-for-woocommerce' ),
            'informative'  => __( 'Informative', 'storeagent-ai-for-woocommerce' ),
        );
    }

    /**
     * Get chat widget settings (helper method for use outside REST API).
     *
     * @return array Chat widget settings.
     */
    public static function get_chat_widget_settings() {
        $defaults       = self::get_default_settings();
        $saved_settings = get_option( self::OPTION_KEY, array() );

        return wp_parse_args( $saved_settings, $defaults );
    }
}
