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

namespace SAAI\AI_Agents;

use SAAI\Abstracts\Abstract_AI_Agent;
use SAAI\Helpers\Helper;
use SAAI\Traits\Singleton_Trait;
use WP_Error;

/**
 * Review_Moderation_AI class.
 *
 * This agent moderates incoming WooCommerce product reviews using AI.
 * It analyzes reviews for spam, inappropriate language, and fake patterns,
 * auto-approving good reviews and flagging problematic ones for admin decision.
 *
 * @since 1.1.4
 */
class Review_Moderation_AI extends Abstract_AI_Agent {

    use Singleton_Trait;

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

    /**
     * Holds the settings data.
     *
     * @since 1.1.4
     * @var array<string, mixed> Settings data.
     */
    protected array $settings;

    /**
     * Meta key for moderation result.
     *
     * @since 1.1.4
     * @var string
     */
    const MODERATION_RESULT_META_KEY = '_saai_review_moderation_result';

    /**
     * Meta key for moderation date.
     *
     * @since 1.1.4
     * @var string
     */
    const MODERATION_DATE_META_KEY = '_saai_review_moderation_date';

    /**
     * Meta key for moderation status.
     *
     * @since 1.1.4
     * @var string
     */
    const MODERATION_STATUS_META_KEY = '_saai_review_moderation_status';

    /**
     * Action Scheduler hook for review moderation.
     *
     * @since 1.1.4
     * @var string
     */
    const MODERATION_ACTION_HOOK = 'saai_review_moderation';

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

        $this->endpoint         = 'review-moderation';
        $this->ai_id            = 'review-moderation-ai';
        $this->data             = $data;
        $this->default_settings = array(
            'enabled'                => 'no',
            'auto_approve_enabled'   => 'no',
            'auto_approve_threshold' => 80,
            'auto_reject_enabled'    => 'no',
            'auto_reject_threshold'  => 20,
            'custom_blacklist'       => '',
            'custom_whitelist'       => '',
            'email_notifications'    => 'yes',
            'language'               => 'default',
        );

        // Initialize settings.
        $this->settings = $this->get_settings();
    }

    /**
     * Run the agent query to moderate a review.
     *
     * @since 1.1.4
     * @param array $params The parameters for the agent query.
     * @return array|\WP_Error An array of moderation results or WP_Error.
     */
    public function run_agent_query( $params = array() ) {
        $comment_id = isset( $params['comment_id'] ) ? (int) $params['comment_id'] : 0;

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

        $comment = get_comment( $comment_id );

        if ( ! $comment ) {
            return new WP_Error(
                'comment_not_found',
                __( 'Comment not found.', 'storeagent-ai-for-woocommerce' )
            );
        }

        // Prepare review data for moderation.
        $product_id = (int) $comment->comment_post_ID;
        $product    = wc_get_product( $product_id );
        $rating     = (int) get_comment_meta( $comment_id, 'rating', true );

        // Check verified purchase status.
        $verified_purchase = false;
        if ( $comment->user_id && $product_id ) {
            $verified_purchase = wc_customer_bought_product(
                $comment->comment_author_email,
                $comment->user_id,
                $product_id
            );
        }

        $review_data = array(
            'review_content'    => $comment->comment_content,
            'reviewer_name'     => $comment->comment_author,
            'reviewer_email'    => $comment->comment_author_email,
            'rating'            => $rating,
            'verified_purchase' => $verified_purchase,
            'custom_blacklist'  => $this->settings['custom_blacklist'] ?? '',
            'custom_whitelist'  => $this->settings['custom_whitelist'] ?? '',
        );

        // Prepare product data so the AI can validate review content against the product.
        $product_data = $this->prepare_product_data( $product );

        $this->set_data(
            array(
                'review_data'  => wp_json_encode( $review_data ),
                'product_data' => wp_json_encode( $product_data ),
                'language'     => Helper::resolve_default_language( $this->settings['language'] ?? 'default' ),
            )
        );
        $ai_response = $this->send_prompt();

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

        // Extract the completion data from the response.
        if ( isset( $ai_response['completion'] ) && is_array( $ai_response['completion'] ) ) {
            return $ai_response['completion'];
        }

        return $ai_response;
    }

    /**
     * Prepare product data for the AI to validate review content.
     *
     * @since 1.1.4
     * @param \WC_Product|false $product The product object.
     * @return array Product data array.
     */
    protected function prepare_product_data( $product ) {
        if ( ! $product instanceof \WC_Product ) {
            return array();
        }

        $product_data = array(
            'product_id'        => $product->get_id(),
            'product_name'      => $product->get_name(),
            'description'       => $product->get_description(),
            'short_description' => $product->get_short_description(),
            'product_url'       => get_permalink( $product->get_id() ),
            'price'             => $product->get_price(),
            'sku'               => $product->get_sku(),
            'categories'        => $this->get_product_categories( $product ),
            'tags'              => $this->get_product_tags( $product ),
        );

        return apply_filters( 'saai_review_moderation_product_data', $product_data, $product );
    }

    /**
     * Get product categories.
     *
     * @since 1.1.4
     * @param \WC_Product $product The product object.
     * @return array Array of category names.
     */
    protected function get_product_categories( $product ) {
        $categories = wp_get_post_terms( $product->get_id(), 'product_cat', array( 'fields' => 'names' ) );
        if ( is_wp_error( $categories ) || ! is_array( $categories ) ) {
            return array();
        }
        return $categories;
    }

    /**
     * Get product tags.
     *
     * @since 1.1.4
     * @param \WC_Product $product The product object.
     * @return array Array of tag names.
     */
    protected function get_product_tags( $product ) {
        $tags = wp_get_post_terms( $product->get_id(), 'product_tag', array( 'fields' => 'names' ) );
        if ( is_wp_error( $tags ) || ! is_array( $tags ) ) {
            return array();
        }
        return $tags;
    }

    /**
     * Normalize a confidence score to integer percentage (0-100).
     *
     * AI responses may return confidence as a decimal (0-1) or integer (0-100).
     * This method normalizes both formats to a consistent integer percentage.
     *
     * @since 1.1.4
     * @param mixed $score The raw confidence score.
     * @return int The normalized confidence score (0-100).
     */
    public static function normalize_confidence_score( $score ) {
        $score = (float) $score;
        if ( $score > 0 && $score <= 1 ) {
            return (int) round( $score * 100 );
        }
        return (int) $score;
    }

    /**
     * Check if a WP_Comment object is a WooCommerce product review.
     *
     * @since 1.1.4
     * @param \WP_Comment|null $comment The comment object.
     * @return bool True if the comment is a product review.
     */
    public static function is_product_review_comment( $comment ) {
        if ( ! $comment || 'review' !== $comment->comment_type ) {
            return false;
        }
        return 'product' === get_post_type( $comment->comment_post_ID );
    }

    /**
     * Check if comment data array represents a WooCommerce product review.
     *
     * @since 1.1.4
     * @param array $commentdata The comment data array.
     * @return bool True if the comment data is for a product review.
     */
    public static function is_product_review_data( $commentdata ) {
        if ( ! isset( $commentdata['comment_type'] ) || 'review' !== $commentdata['comment_type'] ) {
            return false;
        }
        if ( ! empty( $commentdata['comment_post_ID'] ) ) {
            return 'product' === get_post_type( $commentdata['comment_post_ID'] );
        }
        return true;
    }

    /**
     * Get the status labels for moderation statuses.
     *
     * @since 1.1.4
     * @return array<string, string> Associative array of status => translated label.
     */
    public static function get_status_labels() {
        return array(
            'pending'  => __( 'Pending', 'storeagent-ai-for-woocommerce' ),
            'approved' => __( 'Approved', 'storeagent-ai-for-woocommerce' ),
            'flagged'  => __( 'Flagged', 'storeagent-ai-for-woocommerce' ),
            'rejected' => __( 'Rejected', 'storeagent-ai-for-woocommerce' ),
        );
    }

    /**
     * Get the status colors for moderation statuses.
     *
     * @since 1.1.4
     * @return array<string, string> Associative array of status => hex color.
     */
    public static function get_status_colors() {
        return array(
            'pending'  => '#dba617',
            'approved' => '#00a32a',
            'flagged'  => '#d63638',
            'rejected' => '#b32d2e',
        );
    }

    /**
     * Intercept review approval to hold product reviews for moderation.
     *
     * @since 1.1.4
     * @param int|string|WP_Error $approved    The approval status.
     * @param array               $commentdata The comment data.
     * @return int|string|WP_Error The modified approval status.
     */
    public function intercept_review_approval( $approved, $commentdata ) {
        // Only intercept product reviews.
        if ( ! self::is_product_review_data( $commentdata ) ) {
            return $approved;
        }

        // Only intercept reviews that would be approved (1).
        // Leave already-held (0), spam, or trash reviews untouched.
        if ( 1 !== (int) $approved ) {
            return $approved;
        }

        // Hold the review for AI moderation.
        return 0;
    }

    /**
     * Schedule moderation for a review via Action Scheduler.
     *
     * @since 1.1.4
     * @param int $comment_id The comment ID.
     * @return void
     */
    public function schedule_moderation( $comment_id ) {
        // Set initial moderation status.
        update_comment_meta( $comment_id, self::MODERATION_STATUS_META_KEY, 'pending' );

        if ( function_exists( 'as_enqueue_async_action' ) ) {
            as_enqueue_async_action(
                self::MODERATION_ACTION_HOOK,
                array( $comment_id ),
                'saai'
            );
        } elseif ( function_exists( 'as_schedule_single_action' ) ) {
            // Fallback to scheduled action if async is not available.
            as_schedule_single_action(
                time(),
                self::MODERATION_ACTION_HOOK,
                array( $comment_id ),
                'saai'
            );
        }
    }

    /**
     * Process moderation for a review (called by Action Scheduler).
     *
     * @since 1.1.4
     * @param int $comment_id The comment ID.
     * @return void
     */
    public function process_moderation( $comment_id ) {
        // Verify comment still exists and is a product review.
        $comment = get_comment( $comment_id );
        if ( ! self::is_product_review_comment( $comment ) ) {
            return;
        }

        // Run moderation query.
        $result = $this->run_agent_query(
            array(
                'comment_id' => $comment_id,
            )
        );

        if ( is_wp_error( $result ) ) {
            // Log error using WooCommerce logger.
            if ( function_exists( 'wc_get_logger' ) ) {
                wc_get_logger()->error(
                    sprintf( 'Review Moderation AI Error: %s', $result->get_error_message() ),
                    array( 'source' => 'storeagent-ai-for-woocommerce' )
                );
            }
            return;
        }

        // Handle moderation result.
        $this->handle_moderation_result( $comment_id, $result );
    }

    /**
     * Handle moderation result from AI.
     *
     * @since 1.1.4
     * @param int   $comment_id The comment ID.
     * @param array $result     The moderation result.
     * @return void
     */
    protected function handle_moderation_result( $comment_id, $result ) {
        // Store moderation result as comment meta.
        update_comment_meta( $comment_id, self::MODERATION_RESULT_META_KEY, $result );
        update_comment_meta( $comment_id, self::MODERATION_DATE_META_KEY, current_time( 'mysql' ) );

        $confidence = self::normalize_confidence_score( $result['confidence_score'] ?? 0 );
        $decision   = isset( $result['decision'] ) ? $result['decision'] : 'flag';

        // Auto-reject: if enabled and confidence is at or below the reject threshold, trash the review.
        $auto_reject_enabled   = 'yes' === ( $this->settings['auto_reject_enabled'] ?? 'no' );
        $auto_reject_threshold = isset( $this->settings['auto_reject_threshold'] ) ? (int) $this->settings['auto_reject_threshold'] : 20;

        if ( $auto_reject_enabled && $confidence <= $auto_reject_threshold && 'flag' === $decision ) {
            wp_set_comment_status( $comment_id, 'trash' );
            update_comment_meta( $comment_id, self::MODERATION_STATUS_META_KEY, 'rejected' );

            return;
        }

        // Auto-approve: only if enabled in settings.
        $auto_approve_enabled = 'yes' === ( $this->settings['auto_approve_enabled'] ?? 'no' );
        $threshold            = isset( $this->settings['auto_approve_threshold'] ) ? (int) $this->settings['auto_approve_threshold'] : 80;
        $should_auto_approve  = $auto_approve_enabled && $confidence >= $threshold && 'approve' === $decision;

        if ( $should_auto_approve ) {
            wp_set_comment_status( $comment_id, 'approve' );
            update_comment_meta( $comment_id, self::MODERATION_STATUS_META_KEY, 'approved' );
        } else {
            update_comment_meta( $comment_id, self::MODERATION_STATUS_META_KEY, 'flagged' );
            do_action( 'saai_review_moderation_flagged', $comment_id, $result );
        }

        // Re-trigger moderation email with AI results if email notifications are enabled.
        if ( 'yes' === ( $this->settings['email_notifications'] ?? 'yes' ) ) {
            wp_notify_moderator( $comment_id );
        }
    }

    /**
     * Approve a review (notification callback).
     *
     * @since 1.1.4
     * @param array $args The callback arguments containing comment_id.
     * @return bool|WP_Error True on success, WP_Error on failure.
     */
    public function approve_review( $args ) {
        if ( empty( $args['comment_id'] ) ) {
            return new WP_Error( 'missing_comment_id', __( 'Comment ID is required.', 'storeagent-ai-for-woocommerce' ) );
        }

        $comment_id = (int) $args['comment_id'];
        $comment    = get_comment( $comment_id );

        if ( ! $comment ) {
            return new WP_Error( 'comment_not_found', __( 'Comment not found.', 'storeagent-ai-for-woocommerce' ) );
        }

        wp_set_comment_status( $comment_id, 'approve' );
        update_comment_meta( $comment_id, self::MODERATION_STATUS_META_KEY, 'approved' );

        return true;
    }

    /**
     * Reject a review (notification callback).
     *
     * @since 1.1.4
     * @param array $args The callback arguments containing comment_id.
     * @return bool|WP_Error True on success, WP_Error on failure.
     */
    public function reject_review( $args ) {
        if ( empty( $args['comment_id'] ) ) {
            return new WP_Error( 'missing_comment_id', __( 'Comment ID is required.', 'storeagent-ai-for-woocommerce' ) );
        }

        $comment_id = (int) $args['comment_id'];
        $comment    = get_comment( $comment_id );

        if ( ! $comment ) {
            return new WP_Error( 'comment_not_found', __( 'Comment not found.', 'storeagent-ai-for-woocommerce' ) );
        }

        wp_set_comment_status( $comment_id, 'trash' );
        update_comment_meta( $comment_id, self::MODERATION_STATUS_META_KEY, 'rejected' );

        return true;
    }

    /**
     * Append AI moderation results to the WordPress moderation email.
     *
     * @since 1.1.4
     * @param string $message    The email message text.
     * @param int    $comment_id The comment ID.
     * @return string The modified email message.
     */
    public function append_ai_results_to_email( $message, $comment_id ) {
        $result = get_comment_meta( $comment_id, self::MODERATION_RESULT_META_KEY, true );

        if ( ! is_array( $result ) || empty( $result ) ) {
            return $message;
        }

        $ai_section  = "\n\n";
        $ai_section .= "----------------------------------------------\n";
        $ai_section .= __( 'StoreAgent AI Moderation Results', 'storeagent-ai-for-woocommerce' ) . "\n";
        $ai_section .= "----------------------------------------------\n";

        if ( isset( $result['confidence_score'] ) ) {
            $confidence = self::normalize_confidence_score( $result['confidence_score'] );

            /* translators: %d: confidence score percentage. */
            $ai_section .= sprintf( __( 'Confidence Score: %d%%', 'storeagent-ai-for-woocommerce' ), $confidence ) . "\n";
        }

        if ( isset( $result['decision'] ) ) {
            /* translators: %s: AI decision (approve/flag). */
            $ai_section .= sprintf( __( 'AI Decision: %s', 'storeagent-ai-for-woocommerce' ), strtoupper( $result['decision'] ) ) . "\n";
        }

        if ( ! empty( $result['flags'] ) && is_array( $result['flags'] ) ) {
            $ai_section .= __( 'Flags:', 'storeagent-ai-for-woocommerce' ) . ' ' . implode( ', ', $result['flags'] ) . "\n";
        }

        if ( ! empty( $result['reasons'] ) && is_array( $result['reasons'] ) ) {
            $ai_section .= __( 'Reasons:', 'storeagent-ai-for-woocommerce' ) . "\n";
            foreach ( $result['reasons'] as $reason ) {
                $ai_section .= '  - ' . $reason . "\n";
            }
        }

        if ( isset( $result['admin_summary'] ) ) {
            $ai_section .= __( 'Summary:', 'storeagent-ai-for-woocommerce' ) . ' ' . $result['admin_summary'] . "\n";
        }

        $ai_section .= "----------------------------------------------\n";

        return $message . $ai_section;
    }

    /**
     * Suppress default WordPress moderation email for product reviews.
     *
     * @since 1.1.4
     * @param bool $maybe_notify Whether to notify the moderator.
     * @param int  $comment_id   The comment ID.
     * @return bool Whether to notify the moderator.
     */
    public function suppress_review_notification( $maybe_notify, $comment_id ) {
        $comment = get_comment( $comment_id );

        // Only suppress for product reviews.
        if ( ! self::is_product_review_comment( $comment ) ) {
            return $maybe_notify;
        }

        // Check if AI moderation has already run (has result meta).
        $moderation_result = get_comment_meta( $comment_id, self::MODERATION_RESULT_META_KEY, true );

        // If AI has not yet moderated, suppress the email (it will be re-triggered after AI moderation).
        if ( empty( $moderation_result ) ) {
            return false;
        }

        // AI has already run, allow the email through.
        return $maybe_notify;
    }

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

        // Hold product reviews for moderation.
        add_filter( 'pre_comment_approved', array( $this, 'intercept_review_approval' ), 10, 2 );

        // Register Action Scheduler handler.
        add_action( self::MODERATION_ACTION_HOOK, array( $this, 'process_moderation' ), 10, 1 );

        // Suppress default moderation email for reviews until AI moderation completes.
        add_filter( 'notify_moderator', array( $this, 'suppress_review_notification' ), 10, 2 );

        // Append AI results to moderation email when it does fire.
        add_filter( 'comment_moderation_text', array( $this, 'append_ai_results_to_email' ), 10, 2 );

        // Register metabox on the edit comment screen.
        add_action( 'add_meta_boxes_comment', array( $this, 'register_moderation_metabox' ) );

        // Add AI moderation column to the WordPress comments list table.
        add_filter( 'manage_edit-comments_columns', array( $this, 'add_moderation_column' ) );
        add_action( 'manage_comments_custom_column', array( $this, 'display_moderation_column' ), 10, 2 );

        // Add AI moderation column to the WooCommerce product reviews list table.
        add_filter( 'woocommerce_product_reviews_table_columns', array( $this, 'add_moderation_column' ) );
        add_action( 'woocommerce_product_reviews_table_column_saai_moderation', array( $this, 'display_reviews_moderation_column' ) );
    }

    /**
     * Register the AI moderation metabox on the edit comment screen.
     *
     * @since 1.1.4
     * @param \WP_Comment $comment The comment object.
     * @return void
     */
    public function register_moderation_metabox( $comment ) {
        // Only show for product reviews that have been moderated.
        if ( ! self::is_product_review_comment( $comment ) ) {
            return;
        }

        $result = get_comment_meta( $comment->comment_ID, self::MODERATION_RESULT_META_KEY, true );
        if ( empty( $result ) || ! is_array( $result ) ) {
            return;
        }

        $icon_img = '<img src="' . esc_url( SAAI_PLUGIN_URL . 'static/images/storeagent-icon.png' ) . '" width="16" height="16" alt="StoreAgent" style="vertical-align: text-bottom;" />';
        $title    = '<span>' . $icon_img . ' ' . __( 'AI Review Moderation', 'storeagent-ai-for-woocommerce' ) . '</span>';

        add_meta_box(
            'saai-review-moderation',
            $title,
            array( $this, 'display_moderation_metabox' ),
            'comment',
            'normal',
            'high'
        );
    }

    /**
     * Display the AI moderation metabox content.
     *
     * @since 1.1.4
     * @param \WP_Comment $comment The comment object.
     * @return void
     */
    public function display_moderation_metabox( $comment ) {
        $result            = get_comment_meta( $comment->comment_ID, self::MODERATION_RESULT_META_KEY, true );
        $moderation_status = get_comment_meta( $comment->comment_ID, self::MODERATION_STATUS_META_KEY, true );
        $moderation_date   = get_comment_meta( $comment->comment_ID, self::MODERATION_DATE_META_KEY, true );

        // Normalize confidence score for display.
        $confidence = self::normalize_confidence_score( $result['confidence_score'] ?? 0 );

        include SAAI_TEMPLATES_DIR . 'admin/review-moderation-metabox.php';
    }

    /**
     * Get the column header with StoreAgent icon.
     *
     * @since 1.1.4
     * @return string Column header HTML.
     */
    protected function get_moderation_column_header() {
        $icon_img = '<img src="' . esc_url( SAAI_PLUGIN_URL . 'static/images/storeagent-icon.png' ) . '" width="16" height="16" alt="StoreAgent" style="vertical-align: text-bottom;" />';

        return sprintf( '%s %s', $icon_img, __( 'AI Moderation', 'storeagent-ai-for-woocommerce' ) );
    }

    /**
     * Add AI Moderation column to the comments/reviews list table.
     *
     * @since 1.1.4
     * @param array $columns The existing columns.
     * @return array The modified columns.
     */
    public function add_moderation_column( $columns ) {
        $columns['saai_moderation'] = $this->get_moderation_column_header();

        return $columns;
    }

    /**
     * Render the moderation column content for a given comment.
     *
     * @since 1.1.4
     * @param int $comment_id The comment ID.
     * @return void
     */
    protected function render_moderation_column( $comment_id ) {
        $moderation_status = get_comment_meta( $comment_id, self::MODERATION_STATUS_META_KEY, true );

        if ( empty( $moderation_status ) ) {
            echo '&mdash;';
            return;
        }

        $result = get_comment_meta( $comment_id, self::MODERATION_RESULT_META_KEY, true );

        // Normalize confidence score for display.
        $confidence = 0;
        if ( is_array( $result ) && isset( $result['confidence_score'] ) ) {
            $confidence = self::normalize_confidence_score( $result['confidence_score'] );
        }

        include SAAI_TEMPLATES_DIR . 'admin/review-moderation-column.php';
    }

    /**
     * Display the AI Moderation column content in the WordPress comments list table.
     *
     * @since 1.1.4
     * @param string $column     The column name.
     * @param int    $comment_id The comment ID.
     * @return void
     */
    public function display_moderation_column( $column, $comment_id ) {
        if ( 'saai_moderation' !== $column ) {
            return;
        }

        $comment = get_comment( $comment_id );

        // Only show for product reviews.
        if ( ! self::is_product_review_comment( $comment ) ) {
            echo '&mdash;';
            return;
        }

        $this->render_moderation_column( $comment_id );
    }

    /**
     * Display the AI Moderation column content in the WooCommerce product reviews list table.
     *
     * @since 1.1.4
     * @param \WP_Comment $item The review comment object.
     * @return void
     */
    public function display_reviews_moderation_column( $item ) {
        $this->render_moderation_column( $item->comment_ID );
    }
}
