<?php
/**
 * Chat Store Data REST Controller
 *
 * Provides AI with access to store-specific data (products, categories, coupons)
 * for AI coupon generation with specific restrictions.
 *
 * @package SAAI\REST\Chat
 */

namespace SAAI\REST\Chat;

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

defined( 'ABSPATH' ) || exit;

/**
 * Chat_Store_Data class.
 *
 * @since 1.1.4
 */
class Chat_Store_Data extends Abstract_REST {

    use Singleton_Trait;
    use ACFWP_Check_Trait;

    const CACHE_KEY_PREFIX = 'saai_store_data_';
    const CACHE_EXPIRY     = 300; // 5 minutes.

    /**
     * Holds the class instance object.
     *
     * @since 1.1.4
     * @var Chat_Store_Data $instance object
     */
    protected static $instance;

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

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

    /**
     * Register the routes for Store Data endpoint.
     *
     * @since 1.1.4
     * @return void
     */
    public function register_routes() {
        // Store data endpoint for AI coupon generation.
        register_rest_route(
            $this->namespace,
            "/$this->rest_base/store-data",
            array(
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => array( $this, 'get_store_data' ),
                'permission_callback' => array( $this, 'validate_temp_token_permissions' ),
                'args'                => array(
                    'token'  => array(
                        'required'          => true,
                        'type'              => 'string',
                        'description'       => __( 'Temporary authentication token with session ID', 'storeagent-ai-for-woocommerce' ),
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                    'types'  => array(
                        'required'    => false,
                        'type'        => 'array',
                        'default'     => array( 'products', 'categories', 'coupons' ),
                        'description' => __( 'Array of data types to retrieve', 'storeagent-ai-for-woocommerce' ),
                        'items'       => array(
                            'type' => 'string',
                            'enum' => array( 'products', 'categories', 'coupons' ),
                        ),
                    ),
                    'limit'  => array(
                        'required'          => false,
                        'type'              => 'integer',
                        'default'           => 50,
                        'minimum'           => 1,
                        'maximum'           => 100,
                        'description'       => __( 'Maximum number of items per type', 'storeagent-ai-for-woocommerce' ),
                        'sanitize_callback' => 'absint',
                    ),
                    'search' => array(
                        'required'          => false,
                        'type'              => 'string',
                        'description'       => __( 'Search by name, code, or SKU', 'storeagent-ai-for-woocommerce' ),
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                ),
            )
        );
    }

    /**
     * Validate temporary token permissions.
     *
     * @since 1.1.4
     * @param WP_REST_Request $request The request object.
     * @return bool|WP_Error True if valid token, error otherwise.
     */
    public function validate_temp_token_permissions( $request ) {
        // Allow access to the endpoint for admins.
        if ( current_user_can( 'manage_options' ) ) {
            return true;
        }

        $token_param = (string) $request->get_param( 'token' );

        if ( empty( $token_param ) || strpos( $token_param, ':::' ) === false ) {
            return new WP_Error(
                'missing_token',
                __( 'Temporary token is required.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 401 )
            );
        }

        list( $session_id, $token ) = explode( ':::', $token_param, 2 );

        if ( empty( $session_id ) || empty( $token ) ) {
            return new WP_Error(
                'invalid_token_format',
                __( 'Invalid token format.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 401 )
            );
        }

        $session_id   = preg_replace( '/[^a-zA-Z0-9_-]/', '', $session_id );
        $session_data = get_transient( 'saai_session_' . $session_id );

        if ( false === $session_data || ! is_array( $session_data ) || ! isset( $session_data['token'] ) ) {
            return new WP_Error(
                'invalid_token',
                __( 'Invalid or expired temporary token.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 401 )
            );
        }

        // Check if the provided token matches the session token.
        if ( ! hash_equals( $session_data['token'], $token ) ) {
            return new WP_Error(
                'token_mismatch',
                __( 'Token does not match current session.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 401 )
            );
        }

        return true;
    }

    /**
     * Get store data (products, categories, coupons).
     *
     * @since 1.1.4
     * @param WP_REST_Request $request The request object.
     * @return WP_REST_Response|WP_Error The response object or error.
     */
    public function get_store_data( $request ) {
        // Check if ACFWP Premium is active.
        if ( ! $this->is_acfwp_premium_active() ) {
            return new WP_Error(
                'premium_required',
                __( 'Advanced Coupons Premium is required to access store data for AI coupon generation.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 403 )
            );
        }

        $types  = $request->get_param( 'types' );
        $limit  = $request->get_param( 'limit' );
        $search = $request->get_param( 'search' );

        // Ensure types is an array.
        if ( ! is_array( $types ) ) {
            $types = array( 'products', 'categories', 'coupons' );
        }

        // Validate limit.
        if ( $limit < 1 || $limit > 100 ) {
            $limit = 50;
        }

        // Get cached or fresh data.
        $result = $this->get_cached_data( $types, $limit, $search );

        return new WP_REST_Response(
            array(
                'success'   => true,
                'data'      => $result['data'],
                'cached'    => $result['cached'],
                'timestamp' => $result['timestamp'],
            ),
            200
        );
    }

    /**
     * Get cached data or fetch fresh data.
     *
     * @since 1.1.4
     * @param array       $types  Data types to retrieve.
     * @param int         $limit  Maximum items per type.
     * @param string|null $search Search query.
     * @return array Data with cache status.
     */
    private function get_cached_data( $types, $limit, $search ) {
        // Generate cache key based on parameters. Include blog ID for multisite compatibility.
        $cache_key = self::CACHE_KEY_PREFIX . get_current_blog_id() . '_' . md5(
            wp_json_encode(
                array(
                    'types'  => $types,
                    'limit'  => $limit,
                    'search' => $search,
                )
            )
        );

        $cached = get_transient( $cache_key );
        if ( false !== $cached && is_array( $cached ) ) {
            $cached['cached'] = true;
            return $cached;
        }

        // Fetch fresh data.
        $data = array();

        if ( in_array( 'products', $types, true ) ) {
            $data['products'] = $this->get_products_data( $limit, $search );
        }

        if ( in_array( 'categories', $types, true ) ) {
            $data['categories'] = $this->get_categories_data( $limit, $search );
        }

        if ( in_array( 'coupons', $types, true ) ) {
            $data['coupons'] = $this->get_coupons_data( $limit, $search );
        }

        $result = array(
            'data'      => $data,
            'cached'    => false,
            'timestamp' => time(),
        );

        // Store in cache for 5 minutes.
        set_transient( $cache_key, $result, self::CACHE_EXPIRY );

        return $result;
    }

    /**
     * Get products data.
     *
     * @since 1.1.4
     * @param int         $limit  Maximum number of products.
     * @param string|null $search Search query.
     * @return array Products data.
     */
    private function get_products_data( $limit, $search ) {
        $args = array(
            'status' => 'publish',
            'limit'  => $limit,
            'return' => 'ids',
        );

        if ( ! empty( $search ) ) {
            $args['s'] = $search;
        }

        $product_ids = wc_get_products( $args );
        $products    = array();

        foreach ( $product_ids as $product_id ) {
            $product = wc_get_product( $product_id );

            if ( ! $product ) {
                continue;
            }

            $products[] = array(
                'id'         => $product_id,
                'name'       => $product->get_name(),
                'sku'        => $product->get_sku(),
                'price'      => $product->get_regular_price(),
                'sale_price' => $product->get_sale_price(),
            );
        }

        return $products;
    }

    /**
     * Get categories data.
     *
     * @since 1.1.4
     * @param int         $limit  Maximum number of categories.
     * @param string|null $search Search query.
     * @return array Categories data.
     */
    private function get_categories_data( $limit, $search ) {
        $args = array(
            'taxonomy'   => 'product_cat',
            'hide_empty' => false,
            'number'     => $limit,
        );

        if ( ! empty( $search ) ) {
            $args['name__like'] = $search;
        }

        $terms      = get_terms( $args );
        $categories = array();

        if ( is_wp_error( $terms ) ) {
            return $categories;
        }

        foreach ( $terms as $term ) {
            $categories[] = array(
                'id'    => $term->term_id,
                'name'  => $term->name,
                'slug'  => $term->slug,
                'count' => $term->count,
            );
        }

        return $categories;
    }

    /**
     * Get coupons data.
     *
     * @since 1.1.4
     * @param int         $limit  Maximum number of coupons.
     * @param string|null $search Search query.
     * @return array Coupons data.
     */
    private function get_coupons_data( $limit, $search ) {
        $args = array(
            'posts_per_page' => $limit,
            'post_type'      => 'shop_coupon',
            'post_status'    => 'publish',
            'orderby'        => 'date',
            'order'          => 'DESC',
        );

        if ( ! empty( $search ) ) {
            $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(),
                'type'   => $coupon->get_discount_type(),
                'amount' => $coupon->get_amount(),
            );
        }

        return $coupons;
    }
}
