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

namespace SAAI\REST;

use SAAI\Abstracts\Abstract_AI_Agent_REST;
use SAAI\AI_Agents\Product_Questions_AI as AI_Agent;
use SAAI\Classes\Product_Question;
use SAAI\Helpers\Helper;
use SAAI\Traits\Singleton_Trait;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

/**
 * Product_Questions class.
 *
 * @since 1.0.0
 */
class Product_Questions_AI extends Abstract_AI_Agent_REST {

    use Singleton_Trait;

    /**
     * Holds the class instance object
     *
     * @since 1.0.0
     * @var Product_Questions_AI $instance object
     */
    protected static $instance;

    /**
     * Sanitize settings data before saving.
     *
     * @param array $params The parameters to sanitize.
     * @return array The sanitized parameters.
     */
    protected function sanitize_settings_data( $params ) {
        $sanitized = array();

        // Sanitize enabled setting.
        if ( isset( $params['enabled'] ) ) {
            $sanitized['enabled'] = sanitize_text_field( $params['enabled'] );
        }

        // Sanitize tabName (text).
        if ( isset( $params['tabName'] ) ) {
            $sanitized['tabName'] = sanitize_text_field( $params['tabName'] );
        }

        // Sanitize moderateQnA (yes/no).
        if ( isset( $params['moderateQnA'] ) ) {
            $sanitized['moderateQnA'] = sanitize_text_field( $params['moderateQnA'] );
        }

        // Sanitize showDisclaimer (yes/no).
        if ( isset( $params['showDisclaimer'] ) ) {
            $sanitized['showDisclaimer'] = sanitize_text_field( $params['showDisclaimer'] );
        }

        // Sanitize disclaimerText (HTML).
        if ( isset( $params['disclaimerText'] ) ) {
            $sanitized['disclaimerText'] = wp_kses_post( $params['disclaimerText'] );
        }

        // Sanitize questionsAnswers (yes/no).
        if ( isset( $params['questionsAnswers'] ) ) {
            $sanitized['questionsAnswers'] = sanitize_text_field( $params['questionsAnswers'] );
        }

        // Sanitize widget settings.
        if ( isset( $params['enableWidget'] ) ) {
            $sanitized['enableWidget'] = sanitize_text_field( $params['enableWidget'] );
        }

        if ( isset( $params['widgetPosition'] ) ) {
            // Validate widget position (only allow bottom-right or mid-right).
            $position                    = sanitize_text_field( $params['widgetPosition'] );
            $sanitized['widgetPosition'] = in_array( $position, array( 'bottom-right', 'mid-right' ), true ) ? $position : 'bottom-right';
        }

        // Sanitize language (text).
        if ( isset( $params['language'] ) ) {
            $sanitized['language'] = sanitize_text_field( $params['language'] );
        }

        // Sanitize productInfo settings.
        if ( isset( $params['productInfo'] ) && is_array( $params['productInfo'] ) ) {
            $sanitized['productInfo'] = array();

            // Sanitize boolean fields.
            $boolean_fields = array( 'productId', 'description', 'productName', 'price', 'sku', 'attributes' );
            foreach ( $boolean_fields as $field ) {
                if ( isset( $params['productInfo'][ $field ] ) ) {
                    $sanitized['productInfo'][ $field ] = sanitize_text_field( $params['productInfo'][ $field ] );
                }
            }

            // Sanitize metadata array.
            if ( isset( $params['productInfo']['metadata'] ) && is_array( $params['productInfo']['metadata'] ) ) {
                $sanitized['productInfo']['metadata'] = array_map( 'sanitize_text_field', $params['productInfo']['metadata'] );
            }

            // Sanitize enableDataSources (yes/no).
            if ( isset( $params['enableDataSources'] ) ) {
                $sanitized['enableDataSources'] = sanitize_text_field( $params['enableDataSources'] );
            }

            // Sanitize additionalDataSources array.
            if ( isset( $params['dataSources'] ) && is_array( $params['dataSources'] ) ) {
                $sanitized['dataSources'] = array_filter( array_unique( array_map( 'esc_url_raw', $params['dataSources'] ) ) );
            }
        }

        // Apply filter for additional sanitization.
        return apply_filters( 'saai_sanitize_product_questions_settings', $sanitized, $params );
    }

    /**
     * Prepare data sources settings before save.
     *
     * @param array $settings The settings.
     * @param array $params The parameters.
     * @return array The settings.
     */
    public function prepare_data_sources_settings_before_save( $settings, $params ) {
        if ( isset( $params['dataSources'] ) && is_array( $params['dataSources'] ) ) {
            $settings['dataSources'] = $params['dataSources'];
        }

        return $settings;
    }

    /**
     * Register the routes.
     *
     * @since 1.0.0
     * @return void
     */
    public function register_routes() {

        parent::register_routes();

        register_rest_route(
            $this->namespace,
            "/$this->rest_base/(?P<product_id>[\d]+)/ask",
            array(
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => array( $this, 'submit_question' ),
                'permission_callback' => '__return_true',
            )
        );
    }

    /**
     * Submit a question.
     *
     * @param WP_REST_Request $request The request object.
     *
     * @since 1.0.0
     * @return WP_REST_Response|WP_Error
     */
    public function submit_question( $request ) {

        if ( Helper::maybe_throttle_request() ) {
            return new \WP_Error( 'rest_request_throttled', __( 'Request throttled.', 'storeagent-ai-for-woocommerce' ), array( 'status' => 429 ) );
        }

        $product_id = (int) $request->get_param( 'product_id' );
        $product    = wc_get_product( $product_id );

        if ( ! $product ) {
            return new WP_Error( 'invalid_product_id', __( 'Invalid product ID.', 'storeagent-ai-for-woocommerce' ), array( 'status' => 400 ) );
        }

        $original_question = $request->get_param( 'question' );

        $data = array(
            'product_url' => get_permalink( $product_id ),
            'question'    => $original_question,
        );

        // Validate question length to ensure it only has 240 characters max.
        if ( strlen( $original_question ) > 240 ) {
            return new WP_Error( 'question_too_long', __( 'Question must not exceed 240 characters.', 'storeagent-ai-for-woocommerce' ), array( 'status' => 400 ) );
        }

        $ai = AI_Agent::instance();

        $product_info = array(
            'product_id'   => $ai->get_settings( 'productInfo.productId' ) === 'yes' ? $product_id : null,
            'description'  => $ai->get_settings( 'productInfo.description' ) === 'yes' ? $product->get_description() : null,
            'price'        => $ai->get_settings( 'productInfo.price' ) === 'yes' ? $product->get_price() : null,
            'product_name' => $ai->get_settings( 'productInfo.productName' ) === 'yes' ? $product->get_name() : null,
            'SKU'          => $ai->get_settings( 'productInfo.sku' ) === 'yes' ? $product->get_sku() : null,
        );
        if ( $ai->get_settings( 'productInfo.attributes' ) === 'yes' ) {
            $attributes = $product->get_attributes();
            if ( ! empty( $attributes ) ) {
                $product_info['attributes'] = array();
                foreach ( $attributes as $attribute ) {
                    if ( $attribute->is_taxonomy() ) {
                        $taxonomy = $attribute->get_name();
                        $terms    = wc_get_product_terms( $product->get_id(), $taxonomy, array( 'fields' => 'names' ) );

                        $product_info['attributes'][] = array(
                            'name'  => $attribute->get_taxonomy_object()->attribute_label,
                            'value' => $terms,
                        );
                    } else {
                        $product_info['attributes'][] = array(
                            'name'  => $attribute->get_name(),
                            'value' => $attribute->get_options(),
                        );
                    }
                }
            }
        }

        $metas = $ai->get_settings( 'productInfo.metadata' );
        if ( ! empty( $metas ) ) {
            foreach ( $metas as $meta_key ) {
                $product_info[ $meta_key ] = get_post_meta( $product_id, $meta_key, true );
            }
        }

        $data['product_info'] = array_filter( $product_info );

        if ( $ai->get_settings( 'questionsAnswers' ) === 'yes' ) {
            $question_answers = Product_Question::get_questions( $product_id );
            if ( ! empty( $question_answers ) ) {
                $data['questions_answers'] = $question_answers;
            }
        }

        if ( $ai->get_settings( 'enableDataSources' ) === 'yes' ) {
            $data_sources = get_post_meta( $product_id, AI_Agent::PRODUCT_QUESTIONS_DATA_SOURCE_META_KEY, true );
            $data_sources = $data_sources ? array_merge( $data_sources, $ai->get_settings( 'dataSources' ) ) : $ai->get_settings( 'dataSources' );
            if ( is_array( $data_sources ) && ! empty( $data_sources ) ) {
                $data['data_sources'] = implode( "\n", $data_sources );
            }
        }

        $data = apply_filters( 'saai_product_questions_ai_data', $data );

        AI_Agent::instance()->set_data( $data );
        $response = AI_Agent::instance()->send_prompt();
        if ( is_wp_error( $response ) ) {
            return $response;
        }

        [
            'answer'             => $answer,
            'rewritten_question' => $question,
        ] = $response['completion'];

        if ( empty( $answer ) || empty( $question ) ) {
            return new WP_Error( 'empty_answer_or_question', __( 'There was an issue with the request or response.', 'storeagent-ai-for-woocommerce' ), array( 'status' => 400 ) );
        }

        $question_post = new Product_Question( $product_id );

        $question_post->original_question = $original_question;
        $question_post->answer            = $answer;
        $question_post->question          = $question;
        $question_post->save();

        // Trigger notification hook for new questions.
        do_action( 'saai_after_question_submission', $question_post->ID, $question, $product_id );

        $response = array(
            'question' => $original_question,
            'answer'   => $answer,
        );

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

    /**
     * Save response.
     *
     * @param array           $response     The response.
     * @param array           $settings     The updated settings.
     * @param array           $old_settings The previous settings.
     * @param WP_REST_Request $request      The request object.
     *
     * @since 1.0.0
     * @return array
     */
    public function save_response( $response, $settings, $old_settings, $request ) {

        /***************************************************************************
         * Check if the `enabled` setting has changed.
         ***************************************************************************
         *
         * We only need to flush rewrite rules if the `enabled` setting has changed.
         */
        if ( ! $request->get_param( 'enabled' ) || $settings['enabled'] === $old_settings['enabled'] ) {
            return $response;
        }

        /***************************************************************************
         * Flush rewrite rules.
         ***************************************************************************
         *
         * We need to flush rewrite rules as we are (un)registering a new post type.
         */
        flush_rewrite_rules();

        return $response;
    }

    /**
     * Delete product questions when a product is deleted.
     *
     * @param int $product_id The product ID being deleted.
     * @return void
     */
    public function delete_product_questions( $product_id ) {
        // Check if the post being deleted is a product.
        $post = get_post( $product_id );
        if ( ! $post || 'product' !== $post->post_type ) {
            return;
        }

        // Allow third-party to disable this functionality.
        if ( ! apply_filters( 'saai_allow_delete_orphaned_product_questions', true, $product_id ) ) {
            return;
        }

        // Get all questions for this product.
        $args = array(
            'post_type'      => Product_Question::POST_TYPE,
            'posts_per_page' => -1,
            'fields'         => 'ids',
            'meta_query'     => array(
                array(
                    'key'     => '_product_id',
                    'value'   => $product_id,
                    'compare' => '=',
                ),
            ),
        );

        $questions = get_posts( $args );

        // Delete each question.
        foreach ( $questions as $question_id ) {
            wp_delete_post( $question_id, true );
        }
    }

    /**
     * Run the class REST handlers.
     *
     * @since 1.0.0
     * @return void
     */
    public function run() {

        parent::run();

        add_filter( "saai_before_rest_{$this->rest_base}_settings_save", array( $this, 'prepare_data_sources_settings_before_save' ), 10, 2 );
        add_filter( "saai_rest_{$this->rest_base}_settings_save_response", array( $this, 'save_response' ), 10, 4 );

        // Add hook to delete questions when product is deleted.
        add_action( 'before_delete_post', array( $this, 'delete_product_questions' ) );
    }
}
