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

namespace SAAI\AI_Agents;

use SAAI\Abstracts\Abstract_AI_Agent;
use SAAI\Classes\Plan_Manager;
use SAAI\Factories\Vite_App;
use SAAI\Traits\Singleton_Trait;
use SAAI\Traits\Template_Loader;
use SAAI\REST\Product_Tags_Generator_AI as Product_Tags_Generator_AI_REST;
use WP_Error;
use SAAI\Interfaces\Bulk_Run_Agent_Interface;
use SAAI\Helpers\Helper;

/**
 * Product_Tags_Generator_AI class.
 *
 * @since 1.0.0
 */
class Product_Tags_Generator_AI extends Abstract_AI_Agent implements Bulk_Run_Agent_Interface {

    use Singleton_Trait;
    use Template_Loader;

    const GENERATED_TAGS_META_KEY = 'saai_generated_tags';

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

    /**
     * Constructor.
     *
     * @param mixed $data The prompt.
     */
    public function __construct( $data = null ) {

        $this->endpoint         = 'product-tags-generator';
        $this->ai_id            = "$this->endpoint-ai";
        $this->data             = $data;
        $this->default_settings = array(
            'enabled'           => $this->maybe_enable_by_default(),
            'maxTags'           => 10,
            'includeCategories' => 'yes',
            'includeAttributes' => 'yes',
            'language'          => 'default',
        );
    }

    /**
     * Run the agent query.
     *
     * @param array $params The parameters for the agent query.
     *
     * @return array|\WP_Error An array of generated tags or WP_Error.
     */
    public function run_agent_query( $params = array() ) {
        $product_id = (int) $params['product_id'] ?? 0;
        $product    = wc_get_product( $product_id );

        if ( ! $product ) {
            return new \WP_Error(
                'saai_invalid_product_id',
                // translators: %s: product ID.
                sprintf( __( 'Invalid product ID: %s', 'storeagent-ai-for-woocommerce' ), $product_id )
            );
        }

        if ( empty( $product->get_description() ) ) {
            return new \WP_Error(
                'saai_invalid_product_description',
                // translators: %s: product ID.
                sprintf( __( 'Product "%s" is skipped: please ensure that your product has an existing description so the AI can process it via bulk action.', 'storeagent-ai-for-woocommerce' ), $product->get_name() )
            );
        }

        $tags = $this->generate_product_tags( $product );

        if ( is_wp_error( $tags ) ) {
            return new \WP_Error(
                'saai_generate_product_tags_error',
                sprintf(
                    // translators: %s: product ID.
                    __( 'Error generating tags for product "%1$s": %2$s', 'storeagent-ai-for-woocommerce' ),
                    $product->get_name(),
                    $tags->get_error_message()
                )
            );
        }

        return array(
            'completion' => $tags,
        );
    }

    /**
     * Save the object data.
     *
     * @param int|\WC_Product $product The product ID or the product object.
     * @param array           $tags The tags to save.
     * @return bool|\WP_Error
     */
    public function save_object_data( $product, $tags ) {
        $product = $product instanceof \WC_Product ? $product : wc_get_product( $product );

        if ( ! $product ) {
            return new WP_Error( 'invalid_product', __( 'Invalid product ID.', 'storeagent-ai-for-woocommerce' ) );
        }

        if ( ! empty( $tags['tags'] ) ) {
            // $tags sometimes comes back as an array with a 'tags' key.
            $tags = $tags['tags'];
        }

        $terms = array();

        // create new tags if they don't exist.
        foreach ( $tags as $tag ) {
            $term = get_term_by( 'name', $tag, 'product_tag' );

            if ( ! $term ) {
                $data = wp_insert_term( $tag, 'product_tag' );

                if ( is_wp_error( $data ) ) {
                    continue;
                }

                $terms[] = $data['term_id'];
            } else {
                $terms[] = $term->term_id;
            }
        }

        return wp_set_object_terms( $product->get_id(), $terms, 'product_tag' );
    }

    /**
     * Generate tags for a product.
     *
     * @param \WC_Product|int $product The product object.
     *
     * @return array|WP_Error An array of generated tags or WP_Error.
     */
    public function generate_product_tags( $product ) {
        $product = $product instanceof \WC_Product ? $product : wc_get_product( $product );

        if ( ! $product ) {
            return new WP_Error( 'invalid_product', __( 'Invalid product ID.', 'storeagent-ai-for-woocommerce' ) );
        }

        if ( empty( $product->get_description() ) ) {
            return new WP_Error(
                'saai_invalid_product_description',
                // translators: %s: product ID.
                sprintf( __( 'Product "%s" is skipped: please ensure that your product has an existing description so the AI can process it via bulk action.', 'storeagent-ai-for-woocommerce' ), $product->get_name() )
            );
        }

        // Prepare product data for the AI.
        $product_data = array(
            'title'             => $product->get_name(),
            'description'       => $product->get_description(),
            'short_description' => $product->get_short_description(),
        );

        // Include categories if setting is enabled.
        if ( $this->get_settings( 'includeCategories' ) === 'yes' ) {
            $categories = get_the_terms( $product->get_id(), 'product_cat' );
            if ( $categories && ! is_wp_error( $categories ) ) {
                $product_data['categories'] = wp_list_pluck( $categories, 'name' );
            }
        }

        // Include attributes if setting is enabled.
        if ( $this->get_settings( 'includeAttributes' ) === 'yes' ) {
            $attributes                 = $product->get_attributes();
            $product_data['attributes'] = $attributes;
        }

        $data = array(
            'product_data' => wp_json_encode( $product_data ),
            'num_of_tags'  => $this->get_settings( 'maxTags' ),
            'language'     => Helper::resolve_default_language( $this->get_settings( 'language' ) ),
        );

        // Set data for AI request.
        $this->set_data( $data );

        // Send the prompt to the AI.
        $response = $this->send_prompt();

        if ( is_wp_error( $response ) ) {
            return $response;
        }

        if ( ! isset( $response['completion']['tags'] ) || ! is_array( $response['completion']['tags'] ) ) {
            return new WP_Error(
                'invalid_response',
                __( 'Invalid response from AI.', 'storeagent-ai-for-woocommerce' ),
                $response
            );
        }

        // Save the generated tags.
        $tags = $response['completion']['tags'] ?? array();

        return $this->match_with_existing_tags( $tags );
    }

    /**
     * Match the generated tags with the existing tags.
     *
     * @param array $tags The generated tags.
     *
     * @return array The processed tags.
     */
    public function match_with_existing_tags( $tags ) {
        $processed_tags = array();
        foreach ( $tags as $tag ) {
            $tag_slug     = sanitize_title( $tag );
            $existing_tag = get_term_by( 'slug', $tag_slug, 'product_tag' );

            // If the tag exists, add it to the processed tags.
            if ( $existing_tag ) {
                $processed_tags[] = $existing_tag->name;
            } else {
                $processed_tags[] = $tag;
            }
        }
        return array_values( $processed_tags );
    }

    /**
     * Add the AI generate button to the product tag metabox.
     *
     * @return void
     */
    public function add_generate_button_to_tag_metabox() {
        global $post;

        if ( ! $post || get_post_type( $post ) !== 'product' ) {
            return;
        }

        $product_id = $post->ID;
        $has_tags   = get_the_terms( $product_id, 'product_tag' );

        // Load the template with the necessary variables.
        $this->load_template(
            'admin/product-tags-generator-button.php',
            array(
                'product_id' => $product_id,
                'has_tags'   => ! empty( $has_tags ) && ! is_wp_error( $has_tags ),
            )
        );
    }

    /**
     * Enqueue scripts for the product tags metabox.
     *
     * @return void
     */
    public function enqueue_product_tags_admin_scripts() {
        $screen = get_current_screen();

        if ( 'product' !== $screen->id || 'product' !== $screen->post_type ) {
            return;
        }

        // Enqueue dashicons if not already included.
        wp_enqueue_style( 'dashicons' );

        // Initialize Vite_App for the product tags script.
        $product_tags_app = new Vite_App(
            'saai-product-tags-admin',
            'src/vanilla/admin/product-tags-generator/index.ts',
            array( 'jquery' ),
            array_merge(
                array(
                    'productTagsGeneratorRestUrl' => Product_Tags_Generator_AI_REST::instance()->api_url,
                    'wpNonce'                     => wp_create_nonce( 'wp_rest' ),
                ),
                Plan_Manager::get_credit_usage_l10n()
            ),
        );

        // Enqueue the script.
        $product_tags_app->enqueue();

        // Localize script with parameters.
        wp_localize_script(
            'saai-product-tags-admin',
            'saaiProductTagsParams',
            array(
                'generating'         => __( 'Generating tags...', 'storeagent-ai-for-woocommerce' ),
                'success'            => __( 'Tags generated successfully!', 'storeagent-ai-for-woocommerce' ),
                'error'              => __( 'Error generating tags.', 'storeagent-ai-for-woocommerce' ),
                'buttonText'         => __( 'Generate with AI', 'storeagent-ai-for-woocommerce' ),
                'confirmSaveChanges' => __( 'For better results with the generated tags, please save any changes made to the product first. Do you want to proceed?', 'storeagent-ai-for-woocommerce' ),
            )
        );
    }

    /**
     * Run hooks related to the AI agent.
     *
     * @return void
     */
    public function run() {
        if ( ! $this->is_enabled() ) {
            return;
        }

        // Admin functionality.
        add_action( 'admin_footer', array( $this, 'add_generate_button_to_tag_metabox' ) );
        add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_product_tags_admin_scripts' ) );
    }

    /**
     * Maybe enable the AI agent by default.
     *
     * @since 1.0.4
     * @return string
     */
    public function maybe_enable_by_default() {
        global $wpdb;

        /***************************************************************************
         * Query to get the number of product tags.
         ***************************************************************************
         *
         * We need to query the number of product tags to determine if the AI agent
         * should be enabled by default. We are doing this manually because the
         * taxonomy might not be registered yet at the time this is called resulting
         * in a fatal error.
         */
        $tag_count = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(t.term_id)
                FROM {$wpdb->terms} AS t
                INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id
                WHERE tt.taxonomy = %s",
                'product_tag'
            )
        );

        return $tag_count > 1 ? 'yes' : 'no';
    }
}
