<?php
/**
 * Posts List Class
 *
 * @package SAAI
 */

namespace SAAI\Classes\Memory;

use SAAI\Abstracts\Abstract_Class;
use SAAI\Traits\Singleton_Trait;
use SAAI\Classes\Memory\Data_Upload;
use SAAI\Factories\Vite_App;
use SAAI\Classes\Memory\Create_Memory;
use SAAI\Factories\Admin_Notice;
use SAAI\Helpers\Helper;
use SAAI\Classes\Plan_Manager;

defined( 'ABSPATH' ) || exit;

/**
 * Posts List Class
 * Adds AI Memory column to posts list
 */
class Posts_List extends Abstract_Class {

    use Singleton_Trait;

    /**
     * Post meta key for storing post type AI memory enabled status.
     *
     * @since 1.1.2
     */
    const AI_MEMORY_COLUMN_KEY = 'saai_ai_memory';

    /**
     * Transient key for bulk action notices.
     *
     * @since 1.1.2
     */
    const BULK_ACTION_NOTICE_TRANSIENT_KEY = 'saai_ai_memory_bulk_action_notice';

    /**
     * Run the class
     */
    public function run() {
        global $pagenow;

        if ( ! is_admin()
            || ! Create_Memory::instance()->is_memory_created()
            || 'edit.php' !== $pagenow ) {
            return;
        }

        $enabled_post_types = Helper::get_post_types_with_ai_memory_enabled();
        foreach ( $enabled_post_types as $post_type ) {
            add_filter( 'manage_' . $post_type . '_posts_columns', array( $this, 'add_ai_memory_column' ), 999 );
            add_action( 'manage_' . $post_type . '_posts_custom_column', array( $this, 'display_ai_memory_column' ), 10, 2 );
        }

        add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );

        foreach ( $enabled_post_types as $post_type ) {
            add_filter( 'bulk_actions-edit-' . $post_type, array( $this, 'add_bulk_actions' ) );
            add_filter( 'handle_bulk_actions-edit-' . $post_type, array( $this, 'handle_bulk_actions' ), 10, 3 );
            add_action( 'admin_notices', array( $this, 'maybe_register_bulk_action_notices' ) );
        }
    }

    /**
     * Add AI Memory column to product list
     *
     * @param array $columns Existing columns.
     * @return array Modified columns.
     */
    public function add_ai_memory_column( $columns ) {

        $new_columns = array();
        foreach ( $columns as $key => $value ) {
            $new_columns[ $key ] = $value;
            if ( 'date' === $key ) {
                $new_columns[ self::AI_MEMORY_COLUMN_KEY ] = $this->get_column_header();
            }
        }

        return $new_columns;
    }

        /**
         * Get the column header with StoreAgent icon
         *
         * @return string Column header HTML.
         */
    public function get_column_header() {
        $icon_img = '<img src="' . esc_url( SAAI_PLUGIN_URL . 'static/images/storeagent-icon.png' ) . '" width="16" height="16" alt="StoreAgent" />';

        return sprintf(
            '<span class="saai-ai-memory-column-header">%s %s</span>',
            $icon_img,
            __( 'AI Memory', 'storeagent-ai-for-woocommerce' )
        );
    }

    /**
     * Display AI Memory column content
     *
     * @param string $column  Column name.
     * @param int    $post_id Post ID.
     */
    public function display_ai_memory_column( $column, $post_id ) {
        if ( self::AI_MEMORY_COLUMN_KEY !== $column ) {
            return;
        }

        if ( ! is_post_publicly_viewable( $post_id ) || post_password_required( $post_id ) ) {
            printf( '<span class="saai-ai-memory-column-not-viewable"><em>%s</em></span>', esc_html__( 'Not publicly viewable', 'storeagent-ai-for-woocommerce' ) );
            return;
        }

        $this->render_ai_memory_control( $post_id );
    }

    /**
     * Render AI Memory control (switch + status indicator)
     *
     * @param int $post_id Post ID.
     */
    protected function render_ai_memory_control( $post_id ) {
        $is_enabled  = $this->is_ai_memory_enabled( $post_id );
        $status_icon = $this->get_status_icon( $post_id );
        $hover_text  = $this->get_hover_text( $post_id );

        // Ensure status icon is shown when there's hover text (e.g., pending deletion).
        // This handles cases where hover text exists but icon might be empty.
        if ( ! empty( $hover_text ) && empty( $status_icon ) ) {
            $is_uploaded       = $this->is_post_uploaded( $post_id );
            $is_pending_delete = $is_uploaded && ! $is_enabled;

            if ( $is_pending_delete ) {
                $status_icon = $this->get_pending_icon( 'red' );
            }
        }

        // Load template.
        include SAAI_PLUGIN_DIR_PATH . 'templates/admin/ai-memory/posts-list-ai-memory-control.php';
    }

    /**
     * Check if post is uploaded to AI memory
     *
     * @param int $post_id Post ID.
     * @return bool True if uploaded.
     */
    protected function is_post_uploaded( $post_id ) {
        $upload_hash = Helper::get_post_meta( $post_id, Data_Upload::POST_DATA_UPLOAD_HASH_META );
        return ! empty( $upload_hash );
    }

    /**
     * Check if post is pending upload
     *
     * @param int $post_id Post ID.
     * @return bool True if pending upload.
     */
    protected function is_post_pending_upload( $post_id ) {
        $pending = Helper::get_post_meta( $post_id, Data_Upload::PENDING_POST_DATA_UPLOAD_META );
        return 'yes' === $pending;
    }

    /**
     * Check if AI memory is enabled for post
     *
     * @param int $post_id Post ID.
     * @return bool True if enabled.
     */
    protected function is_ai_memory_enabled( $post_id ) {
        $enabled = Helper::get_post_meta( $post_id, Data_Upload::POST_AI_MEMORY_ENABLED_META );
        // Default to enabled if not set.
        return 'no' !== $enabled;
    }

    /**
     * Check if post needs update (data changed since last upload)
     *
     * @param int $post_id Post ID.
     * @return bool True if post type data has changed since last upload.
     */
    protected function is_post_pending_update( $post_id ) {
        $current_hash  = Helper::get_post_meta( $post_id, Data_Upload::POST_DATA_CURRENT_HASH_META );
        $uploaded_hash = Helper::get_post_meta( $post_id, Data_Upload::POST_DATA_UPLOAD_HASH_META );

        // Both hashes must exist and be different for pending update.
        return ! empty( $current_hash ) && ! empty( $uploaded_hash ) && $current_hash !== $uploaded_hash;
    }

    /**
     * Format upload date using WordPress date/time settings
     *
     * @param int $timestamp Unix timestamp.
     * @return string Formatted date or empty string if no timestamp.
     */
    protected function format_post_upload_date( $timestamp ) {
        if ( empty( $timestamp ) ) {
            return '';
        }

        $date_format     = get_option( 'date_format' );
        $time_format     = get_option( 'time_format' );
        $datetime_format = sprintf( '%s %s', $date_format, $time_format );

        return sprintf(
            /* translators: %s: formatted upload date and time */
            __( 'Uploaded: %s', 'storeagent-ai-for-woocommerce' ),
            wp_date( $datetime_format, $timestamp )
        );
    }

    /**
     * Format scheduled upload date using WordPress date/time settings
     *
     * @param string $type Type of schedule (upload or deletion).
     * @return string Formatted scheduled date or fallback message.
     */
    protected function format_scheduled_date( $type = 'upload' ) {
        $next_scheduled = 'upload' === $type ? $this->get_next_upload_schedule() : $this->get_next_deletion_schedule();

        if ( empty( $next_scheduled ) ) {
            return '';
        }

        $date_format     = get_option( 'date_format' );
        $time_format     = get_option( 'time_format' );
        $datetime_format = sprintf( '%s %s', $date_format, $time_format );

        return sprintf(
            /* translators: %s: formatted scheduled date and time */
            __( 'Scheduled: %s', 'storeagent-ai-for-woocommerce' ),
            wp_date( $datetime_format, $next_scheduled )
        );
    }

    /**
     * Get the next scheduled upload time
     *
     * @return int|null Next scheduled timestamp or null if not scheduled.
     */
    protected function get_next_upload_schedule() {
        // Check for scheduled post data upload actions.
        $next_upload = as_next_scheduled_action( Data_Upload::POST_DATA_UPLOAD_HOOK );

        if ( $next_upload ) {
            return $next_upload;
        }

        return null;
    }

    /**
     * Get the next scheduled deletion time
     *
     * @return int|false Next scheduled timestamp or false if not scheduled.
     */
    protected function get_next_deletion_schedule() {
        return as_next_scheduled_action( Data_Upload::POST_DATA_DELETE_HOOK );
    }

    /**
     * Get status icon based on post state
     *
     * @since 1.1.2
     * @param int $post_id Post ID.
     * @return string Status icon HTML.
     */
    public function get_status_icon( $post_id ) {
        $is_enabled        = $this->is_ai_memory_enabled( $post_id );
        $is_uploaded       = $this->is_post_uploaded( $post_id );
        $is_pending_upload = $this->is_post_pending_upload( $post_id );
        $is_pending_update = $this->is_post_pending_update( $post_id );

        if ( $is_enabled && $is_uploaded && $is_pending_update ) {
            return $this->get_pending_icon( 'green' );
        } elseif ( $is_enabled && $is_uploaded ) {
            return $this->get_checkmark_icon();
        } elseif ( $is_enabled && ! $is_uploaded ) {
            return $this->get_pending_icon( 'blue' );
        } elseif ( $is_uploaded && ! $is_enabled ) {
            return $this->get_pending_icon( 'red' );
        }

        return '';
    }

    /**
     * Get hover text for status indicator
     *
     * @param int $post_id Post ID.
     * @return string Hover text.
     */
    public function get_hover_text( $post_id ) {
        $is_enabled        = $this->is_ai_memory_enabled( $post_id );
        $is_uploaded       = $this->is_post_uploaded( $post_id );
        $is_pending_update = $this->is_post_pending_update( $post_id );
        $is_pending_delete = $is_uploaded && ! $is_enabled;

        if ( $is_enabled && $is_uploaded && $is_pending_update ) {
            $scheduled_date = $this->format_scheduled_date();
            return sprintf(
                /* translators: %s: formatted scheduled upload date and time */
                __( 'Post data has been modified and needs to be re-uploaded to the AI memory. %s', 'storeagent-ai-for-woocommerce' ),
                $scheduled_date
            );
        } elseif ( $is_enabled && $is_uploaded ) {
            $upload_timestamp = Helper::get_post_meta( $post_id, Data_Upload::POST_DATA_UPLOAD_TIMESTAMP_META );
            $formatted_date   = $this->format_post_upload_date( $upload_timestamp );
            return sprintf(
                /* translators: %s: formatted upload date and time */
                __( 'Post data has been added to the AI memory. %s', 'storeagent-ai-for-woocommerce' ),
                $formatted_date
            );
        } elseif ( $is_enabled && ! $is_uploaded ) {
            $scheduled_date = $this->format_scheduled_date();
            return sprintf(
                /* translators: %s: formatted scheduled upload date and time */
                __( 'Post data is pending upload to the AI memory. %s', 'storeagent-ai-for-woocommerce' ),
                $scheduled_date
            );
        } elseif ( $is_pending_delete ) {
            $scheduled_date = $this->format_scheduled_date( 'deletion' );
            return sprintf(
                /* translators: %s: formatted scheduled upload date and time */
                __( 'Post data is pending deletion from the AI memory. %s', 'storeagent-ai-for-woocommerce' ),
                $scheduled_date
            );
        }

        return '';
    }

    /**
     * Get checkmark icon SVG
     *
     * @return string SVG icon.
     */
    protected function get_checkmark_icon() {
        return '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="color: #46b450;">
            <path d="M9,20.42L2.79,14.21L5.62,11.38L9,14.77L18.88,4.88L21.71,7.71L9,20.42Z"/>
        </svg>';
    }

    /**
     * Get pending icon SVG
     *
     * @param string $color Icon color (blue, red, or green).
     * @return string SVG icon.
     */
    protected function get_pending_icon( $color = 'blue' ) {
        $colors = array(
            'blue'  => '#0073aa',
            'red'   => '#dc3232',
            'green' => '#46b450',
        );

        $fill_color = $colors[ $color ] ?? $colors['blue'];

        return '<svg width="16" height="16" viewBox="0 0 24 24" fill="' . $fill_color . '">
            <circle cx="6" cy="12" r="2"/>
            <circle cx="12" cy="12" r="2"/>
            <circle cx="18" cy="12" r="2"/>
        </svg>';
    }

    /**
     * Enqueue scripts for the posts list
     *
     * @param string $hook Current admin page hook.
     */
    public function enqueue_scripts( $hook ) {
        if ( 'edit.php' !== $hook || ! in_array( get_current_screen()->post_type, Helper::get_post_types_with_ai_memory_enabled(), true ) ) {
            return;
        }

        $screen    = get_current_screen();
        $post_type = $screen->post_type ?? 'post';

        $l10n_data = array(
            'ajaxUrl' => rest_url( 'storeagent-ai/v1/chat-post-types/toggle-post' ),
            'nonce'   => wp_create_nonce( 'wp_rest' ),
        );

        // Add bulk run agent data for products.
        if ( 'product' === $post_type ) {
            $l10n_data['bulkRunAgentOptions'] = \SAAI\Classes\Bulk_Run_Agent::get_bulk_ai_agent_options();
            $l10n_data['bulkRunAgentNonce']   = wp_create_nonce( 'saai_bulk_run_agent' );

            // Add AI tasks usage data for pre-flight credit check.
            $plan_manager = Plan_Manager::instance();
            $plan_data    = $plan_manager->get_plan_data();
            $current_plan = $plan_manager->normalize_plan_name( $plan_data['plan_name'] ?? 'lite' );
            $ai_limit     = $plan_data['limits']['ai_actions'] ?? 0;
            $ai_used      = $plan_data['usage']['ai_actions'] ?? 0;

            $l10n_data['aiTasksUsed']      = $ai_used;
            $l10n_data['aiTasksLimit']     = $ai_limit;
            $l10n_data['currentPlan']      = $current_plan;
            $l10n_data['nextPlanName']     = $plan_manager->get_next_plan_name( $current_plan );
            $l10n_data['upgradeUrl']       = esc_url_raw(
                Helper::get_utm_url( 'pricing', 'saai', 'bulk-run-modal', 'upgrade' )
            );
            $l10n_data['connectionTabUrl'] = esc_url_raw(
                add_query_arg(
                    array(
                        'page' => 'storeagent-ai',
                        'path' => '/settings/connection',
                    ),
                    admin_url( 'admin.php' )
                )
            );
            $l10n_data['pluginDirUrl']     = SAAI_PLUGIN_URL;
        }

        $vite_app = new Vite_App(
            'saai-posts-list-ai-memory',
            'src/vanilla/admin/posts-list/index.ts',
            array( 'jquery' ),
            $l10n_data,
            'saaiObj'
        );

        $vite_app->enqueue();
    }

    /**
     * Add bulk actions for AI memory
     *
     * @param array $actions Existing bulk actions.
     * @return array Modified bulk actions.
     */
    public function add_bulk_actions( $actions ) {
        $actions['saai_add_to_ai_memory']      = __( 'Add to AI Memory', 'storeagent-ai-for-woocommerce' );
        $actions['saai_remove_from_ai_memory'] = __( 'Remove from AI Memory', 'storeagent-ai-for-woocommerce' );
        return $actions;
    }

    /**
     * Handle bulk actions for AI memory
     *
     * @param string $redirect_to Redirect URL.
     * @param string $action Action name.
     * @param array  $ids Post IDs.
     * @return string Modified redirect URL.
     */
    public function handle_bulk_actions( $redirect_to, $action, $ids ) {
        if ( ! current_user_can( 'manage_woocommerce' ) ) {
            wp_die( esc_html__( 'You do not have sufficient permissions to perform this action.', 'storeagent-ai-for-woocommerce' ) );
        }

        $ids       = array_map( 'absint', $ids );
        $processed = 0;
        $type      = '';

        // Handle add to AI memory bulk action.
        if ( 'saai_add_to_ai_memory' === $action ) {
            foreach ( $ids as $id ) {
                // Only process posts that are published and have AI memory disabled.
                if ( get_post_status( $id ) === 'publish' && ! $this->is_ai_memory_enabled( $id ) ) {
                    Helper::update_post_meta( $id, Data_Upload::POST_AI_MEMORY_ENABLED_META, 'yes' );

                    Data_Upload::instance()->maybe_schedule_post_data_upload( get_post_type( $id ) );

                    ++$processed;
                }
            }

            $type = 'added';

        } elseif ( 'saai_remove_from_ai_memory' === $action ) { // Handle remove from AI memory bulk action.
            foreach ( $ids as $id ) {
                // Only process posts that are published and have AI memory enabled.
                if ( get_post_status( $id ) === 'publish' && $this->is_ai_memory_enabled( $id ) ) {
                    Helper::update_post_meta( $id, Data_Upload::POST_AI_MEMORY_ENABLED_META, 'no' );

                    // Trigger deletion action for each post.
                    do_action( 'saai_post_ai_memory_disabled', $id, get_post_type( $id ) );

                    ++$processed;
                }
            }

            $type = 'removed';
        }

        // Set transient for bulk action notice.
        if ( $type ) {
            set_transient(
                self::BULK_ACTION_NOTICE_TRANSIENT_KEY,
                array(
                    'type'  => $type,
                    'count' => $processed,
                ),
                60 * 5 // 5 minutes
            );
        }

        return $redirect_to;
    }

    /**
     * Display bulk action notices
     */
    public function maybe_register_bulk_action_notices() {

        global $typenow;

        $notice = get_transient( self::BULK_ACTION_NOTICE_TRANSIENT_KEY );

        if ( ! $notice ) {
            return;
        }

        $post_type      = get_post_type_object( $typenow );
        $singular_label = strtolower( $post_type->labels->singular_name );
        $plural_label   = strtolower( $post_type->labels->name );

        $type        = $notice['type'];
        $count       = $notice['count'];
        $notice_type = 'success';

        if ( 0 >= $count && 'added' === $type ) {
            $message = sprintf(
                /* translators: %1$s: singular label, %2$s: plural label */
                __( 'No %1$s were processed. The selected %2$s may already be added to AI memory or in a pending state.', 'storeagent-ai-for-woocommerce' ),
                $plural_label,
                $plural_label
            );
            $notice_type = 'info';
        } elseif ( 'added' === $type && 0 < $count ) {
            $message = sprintf(
                /* translators: %1$d: number of posts, %2$s: singular label */
                _n( '%1$d %2$s has been scheduled to be added to AI memory. The upload will be processed in the background.', '%1$d %2$s have been scheduled to be added to AI memory. The upload will be processed in the background.', $count, 'storeagent-ai-for-woocommerce' ),
                $count,
                $singular_label
            );
        } elseif ( 0 >= $count && 'removed' === $type ) {
            $message = sprintf(
                /* translators: %1$s: singular label, %2$s: plural label */
                __( 'No %1$s were processed. The selected %2$s may already be removed from AI memory or in a pending state.', 'storeagent-ai-for-woocommerce' ),
                $plural_label,
                $plural_label
            );
            $notice_type = 'info';
        } elseif ( 'removed' === $type && 0 < $count ) {
            $message = sprintf(
                /* translators: %1$d: number of posts, %2$s: singular label */
                _n( '%1$d %2$s has been scheduled to be removed from AI memory. The removal will be processed in the background.', '%1$d %2$s have been scheduled to be removed from AI memory. The removal will be processed in the background.', $count, 'storeagent-ai-for-woocommerce' ),
                $count,
                $singular_label
            );
        }

        $admin_notice = new Admin_Notice( $message, $notice_type );
        $admin_notice->run();

        delete_transient( 'saai_ai_memory_bulk_action_notice' );
    }
}
