<?php

/**
 * Main SlideMind plugin class
 *
 * @package SlideMind
 * @since 2.0.0
 */
namespace SlideMind;

if ( !defined( 'ABSPATH' ) ) {
    exit;
}
class Plugin {
    /**
     * Singleton instance
     * @var Plugin|null
     */
    private static $instance = null;

    /**
     * Plugin version
     * @var string
     */
    private $version;

    /**
     * Plugin path
     * @var string
     */
    private $plugin_path;

    /**
     * Plugin URL
     * @var string
     */
    private $plugin_url;

    /**
     * Core component instances
     */
    private $api_key_manager;

    private $config_repository;

    private $prompt_engine;

    private $llm_proxy;

    /**
     * Core component instances (templates + memory + export)
     */
    private $template_manager;

    private $learner_memory;

    private $config_exporter;

    private $full_exporter;

    private $import_parser;

    private $full_importer;

    /**
     * Admin component instances
     */
    private $admin_menu;

    private $settings_page;

    private $configurations_page;

    private $templates_page;

    private $sandbox_controller;

    private $export_tool_page;

    private $import_tool_page;

    private $downgrade_notice;

    private $memory_admin_page;

    /**
     * Premium component instances (null in free zip)
     */
    private $cors_handler;

    private $license_state_watcher;

    private $learner_detail_page;

    private $analytics_dashboard;

    private $content_admin;

    /**
     * Frontend instances
     */
    private $embed_shortcode;

    private $chat_widget;

    /**
     * Privacy management (GDPR)
     */
    private $privacy;

    /**
     * Get the singleton plugin instance
     *
     * @return Plugin
     */
    public static function instance() {
        if ( is_null( self::$instance ) ) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Private constructor (singleton)
     */
    private function __construct() {
        $this->version = SLIDEMIND_VERSION;
        $this->plugin_path = SLIDEMIND_PLUGIN_PATH;
        $this->plugin_url = SLIDEMIND_PLUGIN_URL;
        $this->maybe_upgrade_db();
        $this->load_dependencies();
        $this->init_components();
        $this->init_hooks();
    }

    /**
     * Check if the database needs updating and run migration
     */
    private function maybe_upgrade_db() {
        require_once $this->plugin_path . 'includes/class-activator.php';
        Activator::maybe_upgrade();
    }

    /**
     * Load dependencies
     */
    private function load_dependencies() {
        // Core
        require_once $this->plugin_path . 'includes/Core/class-api-key-manager.php';
        require_once $this->plugin_path . 'includes/Core/class-config-repository.php';
        require_once $this->plugin_path . 'includes/Core/class-prompt-engine.php';
        require_once $this->plugin_path . 'includes/Core/class-llm-proxy.php';
        require_once $this->plugin_path . 'includes/Core/class-template-manager.php';
        require_once $this->plugin_path . 'includes/Core/class-learner-memory.php';
        require_once $this->plugin_path . 'includes/Core/class-learner-identity.php';
        require_once $this->plugin_path . 'includes/Core/class-config-access.php';
        require_once $this->plugin_path . 'includes/Core/class-config-exporter.php';
        require_once $this->plugin_path . 'includes/Core/class-bulk-data-manager.php';
        require_once $this->plugin_path . 'includes/Core/class-full-exporter.php';
        require_once $this->plugin_path . 'includes/Core/class-import-manifest.php';
        require_once $this->plugin_path . 'includes/Core/class-import-sanitizer.php';
        require_once $this->plugin_path . 'includes/Core/class-import-parser.php';
        require_once $this->plugin_path . 'includes/Core/class-full-importer.php';
        require_once $this->plugin_path . 'includes/Core/class-privacy.php';
        // API
        require_once $this->plugin_path . 'includes/API/class-chat-endpoint.php';
        require_once $this->plugin_path . 'includes/API/class-memory-endpoint.php';
        require_once $this->plugin_path . 'includes/API/class-sandbox-endpoint.php';
        require_once $this->plugin_path . 'includes/API/class-whoami-endpoint.php';
        require_once $this->plugin_path . 'includes/API/class-bootstrap-endpoint.php';
        // Frontend
        require_once $this->plugin_path . 'includes/Frontend/class-embed-shortcode.php';
        require_once $this->plugin_path . 'includes/Frontend/class-chat-widget.php';
        // Admin (loaded only in admin context)
        if ( is_admin() ) {
            require_once $this->plugin_path . 'includes/Admin/class-admin-menu.php';
            require_once $this->plugin_path . 'includes/Admin/class-settings-page.php';
            require_once $this->plugin_path . 'includes/Admin/class-configurations-page.php';
            // Custom-templates admin (class-templates-page.php) is a paid
            // feature, required inside the premium-only block below.
            require_once $this->plugin_path . 'includes/Admin/class-sandbox-controller.php';
            require_once $this->plugin_path . 'includes/Admin/class-export-tool-page.php';
            require_once $this->plugin_path . 'includes/Admin/class-import-tool-page.php';
            // DowngradeNotice ships in the free build too: it reads a persistent
            // option (set by the premium watcher before a downgrade) so a former
            // Pro user installing the free zip is told their data is preserved.
            require_once $this->plugin_path . 'includes/Admin/class-downgrade-notice.php';
            require_once $this->plugin_path . 'includes/Admin/class-memory-admin-page.php';
        }
    }

    /**
     * Initialize components
     */
    private function init_components() {
        // Core
        $this->api_key_manager = new Core\ApiKeyManager();
        $this->config_repository = new Core\ConfigRepository($this->api_key_manager);
        $this->prompt_engine = new Core\PromptEngine();
        $this->learner_memory = new Core\LearnerMemory();
        $this->llm_proxy = new Core\LLMProxy($this->api_key_manager, $this->prompt_engine, $this->learner_memory);
        $this->template_manager = new Core\TemplateManager($this->config_repository);
        $this->config_exporter = new Core\ConfigExporter($this->config_repository);
        $this->full_exporter = new Core\FullExporter($this->config_repository, $this->template_manager);
        $this->import_parser = new Core\ImportParser();
        $this->full_importer = new Core\FullImporter($this->config_repository, $this->template_manager);
        $this->privacy = new Core\Privacy($this->learner_memory);
        // Admin
        if ( is_admin() ) {
            $this->admin_menu = new Admin\AdminMenu();
            $this->settings_page = new Admin\SettingsPage($this->api_key_manager);
            $this->configurations_page = new Admin\ConfigurationsPage(
                $this->config_repository,
                $this->llm_proxy,
                $this->learner_memory,
                $this->template_manager,
                $this->config_exporter
            );
            // Custom-templates admin page is instantiated in the premium block.
            $this->sandbox_controller = new Admin\SandboxController($this->prompt_engine, $this->config_repository);
            $this->export_tool_page = new Admin\ExportToolPage($this->full_exporter);
            $this->import_tool_page = new Admin\ImportToolPage($this->import_parser, $this->full_importer);
            $this->downgrade_notice = new Admin\DowngradeNotice();
            $this->memory_admin_page = new Admin\MemoryAdminPage();
        }
        // Frontend
        $this->embed_shortcode = new Frontend\EmbedShortcode();
        $this->chat_widget = new Frontend\ChatWidget($this->config_repository, $this->prompt_engine, $this->learner_memory);
    }

    /**
     * Initialize WordPress hooks
     */
    private function init_hooks() {
        // Register CPT
        add_action( 'init', [$this, 'register_post_type'] );
        // Register REST endpoints
        add_action( 'rest_api_init', [$this, 'register_rest_routes'] );
        // Capabilities
        add_filter(
            'map_meta_cap',
            [$this, 'map_meta_capabilities'],
            10,
            4
        );
        // Memory hooks (cache invalidation, user deletion, cron purge)
        add_action( 'user_register', [$this->learner_memory, 'invalidate_user_cache'] );
        add_action( 'profile_update', [$this->learner_memory, 'invalidate_user_cache'] );
        add_action( 'delete_user', [$this, 'on_delete_user'] );
        add_action( 'slidemind_purge_memory_cron', [$this, 'purge_old_memory'] );
        // Privacy (GDPR / WP Privacy Tools)
        $this->privacy->register_hooks();
        // Log purge cron
        add_action( 'slidemind_purge_logs_cron', [$this, 'purge_old_logs'] );
        // One-time migration: memory mode slides → QA + draft
        if ( is_admin() ) {
            add_action( 'admin_init', [$this, 'migrate_memory_mode_slides'] );
            add_action( 'admin_notices', [$this, 'show_memory_migration_notice'] );
        }
    }

    /**
     * One-time migration: converts slides in memory mode to QA + draft.
     * Memory variables meta are preserved.
     */
    public function migrate_memory_mode_slides() : void {
        if ( get_option( 'slidemind_memory_mode_migrated' ) ) {
            return;
        }
        $posts = get_posts( [
            'post_type'      => 'slidemind_config',
            'meta_query'     => [[
                'key'   => '_slidemind_config_type',
                'value' => 'slide',
            ], [
                'key'   => '_slidemind_widget_mode',
                'value' => 'memory',
            ]],
            'posts_per_page' => -1,
            'post_status'    => 'any',
            'fields'         => 'ids',
        ] );
        $count = count( $posts );
        foreach ( $posts as $post_id ) {
            update_post_meta( $post_id, '_slidemind_widget_mode', 'qa' );
            wp_update_post( [
                'ID'          => $post_id,
                'post_status' => 'draft',
            ] );
        }
        update_option( 'slidemind_memory_mode_migrated', true );
        if ( $count > 0 ) {
            set_transient( 'slidemind_memory_migration_notice', $count, 60 );
        }
    }

    /**
     * Displays a one-time admin notice after memory mode migration.
     */
    public function show_memory_migration_notice() : void {
        $count = get_transient( 'slidemind_memory_migration_notice' );
        if ( !$count ) {
            return;
        }
        delete_transient( 'slidemind_memory_migration_notice' );
        printf( '<div class="notice notice-info is-dismissible"><p><strong>SlideMind:</strong> %s</p></div>', esc_html( sprintf( 
            /* translators: %d: number of migrated slides */
            _n(
                '%d slide in Memory mode has been converted to Q&A (draft). Memory variables are preserved. Please review and republish.',
                '%d slides in Memory mode have been converted to Q&A (draft). Memory variables are preserved. Please review and republish.',
                $count,
                'slidemind'
            ),
            $count
         ) ) );
    }

    /**
     * Purge learner memory when a WP user is deleted
     *
     * @param int $user_id
     */
    public function on_delete_user( int $user_id ) : void {
        $this->learner_memory->purge_user( $user_id );
    }

    /**
     * Delete logs older than the configured retention period
     */
    public function purge_old_logs() : void {
        global $wpdb;
        $settings = get_option( 'slidemind_settings', [] );
        $days = max( 1, (int) ($settings['log_retention_days'] ?? 90) );
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}slidemind_logs WHERE created_at < DATE_SUB(NOW(), INTERVAL %d DAY)", $days ) );
    }

    /**
     * Delete learner memory entries exceeding the configured retention period
     */
    public function purge_old_memory() : void {
        $settings = get_option( 'slidemind_settings', [] );
        $days = (int) ($settings['memory_retention_days'] ?? 0);
        // Purge authenticated learner memory (0 = keep forever)
        if ( $days > 0 ) {
            global $wpdb;
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
            $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}slidemind_learner_memory WHERE wp_user_id > 0 AND updated_at < DATE_SUB(NOW(), INTERVAL %d DAY)", $days ) );
        }
        // Purge expired anonymous sessions
        $anon_ttl = (int) ($settings['anonymous_session_ttl'] ?? 24);
        if ( $anon_ttl > 0 ) {
            $this->learner_memory->purge_expired_sessions( $anon_ttl );
        }
    }

    /**
     * Register the Custom Post Type
     */
    public function register_post_type() {
        $labels = [
            'name'               => __( 'AI Configurations', 'slidemind' ),
            'singular_name'      => __( 'AI Configuration', 'slidemind' ),
            'menu_name'          => 'SlideMind',
            'all_items'          => __( 'All configurations', 'slidemind' ),
            'add_new_item'       => __( 'Add a configuration', 'slidemind' ),
            'add_new'            => __( 'Add', 'slidemind' ),
            'edit_item'          => __( 'Edit configuration', 'slidemind' ),
            'update_item'        => __( 'Update', 'slidemind' ),
            'search_items'       => __( 'Search', 'slidemind' ),
            'not_found'          => __( 'No configuration found', 'slidemind' ),
            'not_found_in_trash' => __( 'No configuration in trash', 'slidemind' ),
        ];
        $args = [
            'label'           => __( 'AI Configuration', 'slidemind' ),
            'description'     => __( 'AI configurations for e-learning modules', 'slidemind' ),
            'labels'          => $labels,
            'supports'        => ['title', 'author', 'revisions'],
            'public'          => false,
            'show_ui'         => true,
            'show_in_menu'    => false,
            'menu_position'   => 30,
            'menu_icon'       => 'dashicons-format-chat',
            'capability_type' => 'slidemind_config',
            'map_meta_cap'    => true,
            'show_in_rest'    => false,
            'has_archive'     => false,
            'rewrite'         => false,
        ];
        register_post_type( 'slidemind_config', $args );
    }

    /**
     * Register REST API routes
     */
    public function register_rest_routes() {
        // Main chat endpoint
        $chat_endpoint = new API\ChatEndpoint($this->config_repository, $this->llm_proxy, $this->learner_memory);
        $chat_endpoint->register_routes();
        // Learner memory endpoint
        $memory_endpoint = new API\MemoryEndpoint($this->config_repository, $this->learner_memory);
        $memory_endpoint->register_routes();
        // Sandbox endpoint (manual mode)
        // Note: SandboxController may not be instantiated outside admin context
        $sandbox_controller = $this->sandbox_controller;
        if ( !$sandbox_controller ) {
            // Create a temporary instance if not in admin context
            require_once $this->plugin_path . 'includes/Admin/class-sandbox-controller.php';
            $sandbox_controller = new Admin\SandboxController($this->prompt_engine, $this->config_repository);
        }
        $sandbox_endpoint = new API\SandboxEndpoint(
            $this->llm_proxy,
            $this->prompt_engine,
            $this->api_key_manager,
            $sandbox_controller
        );
        $sandbox_endpoint->register_routes();
        // Whoami endpoint (learner identification)
        $whoami_endpoint = new API\WhoamiEndpoint();
        $whoami_endpoint->register_routes();
        // Bootstrap endpoint (nonce + identity issuance for chat/memory clients)
        $bootstrap_endpoint = new API\BootstrapEndpoint($this->config_repository);
        $bootstrap_endpoint->register_routes();
    }

    /**
     * Map custom capabilities
     */
    public function map_meta_capabilities(
        $caps,
        $cap,
        $user_id,
        $args
    ) {
        // Map slidemind_config capabilities to post capabilities
        $capability_map = [
            'edit_slidemind_config'          => 'edit_post',
            'read_slidemind_config'          => 'read_post',
            'delete_slidemind_config'        => 'delete_post',
            'edit_slidemind_configs'         => 'edit_posts',
            'edit_others_slidemind_configs'  => 'edit_others_posts',
            'publish_slidemind_configs'      => 'publish_posts',
            'read_private_slidemind_configs' => 'read_private_posts',
        ];
        if ( isset( $capability_map[$cap] ) ) {
            $caps = [$capability_map[$cap]];
        }
        return $caps;
    }

    /**
     * Component getters
     */
    public function get_api_key_manager() {
        return $this->api_key_manager;
    }

    public function get_config_repository() {
        return $this->config_repository;
    }

    public function get_prompt_engine() {
        return $this->prompt_engine;
    }

    public function get_llm_proxy() {
        return $this->llm_proxy;
    }

    public function get_template_manager() {
        return $this->template_manager;
    }

    public function get_learner_memory() {
        return $this->learner_memory;
    }

    public function get_config_exporter() {
        return $this->config_exporter;
    }

    public function get_full_exporter() {
        return $this->full_exporter;
    }

    public function get_import_parser() {
        return $this->import_parser;
    }

    public function get_full_importer() {
        return $this->full_importer;
    }

    public function get_export_tool_page() {
        return $this->export_tool_page;
    }

    public function get_import_tool_page() {
        return $this->import_tool_page;
    }

    public function get_sandbox_controller() {
        return $this->sandbox_controller;
    }

    public function get_version() {
        return $this->version;
    }

    public function get_plugin_path() {
        return $this->plugin_path;
    }

    public function get_plugin_url() {
        return $this->plugin_url;
    }

    /**
     * Prevent cloning
     */
    private function __clone() {
    }

    /**
     * Prevent unserialization
     */
    public function __wakeup() {
        throw new \Exception('Cannot unserialize singleton');
    }

}
