<?php

namespace AIPT\Core;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use AIPT\Api\RestEndpoints;
use AIPT\Api\BulkGenerator\Desc\Controllers\GenerationController as NewGenerationController;
use AIPT\Api\BulkGenerator\Desc\Controllers\ContentController;
use AIPT\Api\BulkGenerator\FAQ\FAQGeneratorController;
use AIPT\Api\BulkGenerator\FAQ\FAQGeneratorService;
use AIPT\Api\BulkGenerator\FAQ\FAQDisplaySettings;
use AIPT\Api\BulkGenerator\FAQ\FAQDisplaySettingsController;
use AIPT\Api\BulkGenerator\FAQ\FAQFrontendRenderer;
use AIPT\Api\BulkGenerator\FAQ\FAQSchemaGenerator;
use AIPT\Api\BulkGenerator\FAQ\FAQShortcode;
use AIPT\Api\BulkGenerator\Standard\StandardBulkGeneratorController;
use AIPT\Api\BulkGenerator\Title\TitleGeneratorController;
use AIPT\Api\BulkGenerator\SeoMeta\SeoMetaGeneratorController;
use AIPT\Core\FsManager;
use AIPT\Utils\PremiumFeatureManager;
use AIPT\Api\CustomFields;
use AIPT\Core\CreditSystem\CreditRest;
use AIPT\Utils\Encryption;
use AIPT\Admin\NoticeManager;
use AIPT\Api\StoreIndex\StoreIndexController;
use AIPT\Api\StoreIndex\IndexBuilder;
use AIPT\Api\StoreIndex\IndexSettings;
use AIPT\Api\StoreIndex\IndexStorage;
use AIPT\Api\Chatbot\ChatbotController;
use AIPT\Api\Chatbot\Jobs\ChatbotJobWorker;
use AIPT\Api\Constants\ChatbotConstants;
use AIPT\Api\PromptTemplates\PromptTemplateController;

use AIPT\Api\PromptBuilder\PromptAssembler;
use AIPT\Api\PromptBuilder\PromptBuilderController;
use AIPT\Api\PromptBuilder\WizardSchemaRegistry;
use AIPT\Api\TaxonomyGenerator\TaxonomyGeneratorController;
use AIPT\Api\Services\RestAPIClientFactory;
use AIPT\Core\Services\UiVariantService;
use AIPT\Core\Services\WordPressRuntimeDetector;
use AIPT\Utils\Credentials\CredentialResolver;
use AIPT\Api\Dashboard\DashboardController;
use AIPT\Api\BulkGenerator\ImageAlt\ImageAltController;
use AIPT\Api\UiVariant\UiVariantHealthController;
use AIPT\Api\UiPrefs\UiPrefsController;
use AIPT\Api\PricingPreview\PricingPreviewController;
use AIPT\Core\Telemetry\VariantTelemetryReporter;

class Init {
    private static $instance = null;
    private $generation_controller;
    private $content_controller;
    private $standard_bulk_generator_controller;
    private $title_generator_controller;
    private $faq_generator_controller;
    private $seo_meta_generator_controller;
    private $taxonomy_generator_controller;
    private $fsManager;
    private $premiumFeatureManager;
    private $custom_fields;
    private $credit_rest_controller;
    private $store_index_controller;
    private $chatbot_controller;
    private $prompt_template_controller;
    private $prompt_builder_controller;
    private $dashboard_controller;
    private $image_alt_controller;
    private $ui_variant_health_controller;
    private $ui_prefs_controller;
    private $pricing_preview_controller;

    private $asset_enqueuer;
    private $localization_data_builder;
    private $options_cache_service;
    private $admin_menu_manager;
    private $capability_manager;
    private $cron_scheduler;
    private $ability_registrar;

    /**
     * Flag to prevent duplicate chatbot container rendering.
     * Used for wp_body_open/wp_footer fallback mechanism.
     *
     * @var bool
     */
    private $chatbot_container_rendered = false;

    private function is_development_mode(): bool {
        return defined('WP_DEBUG') && WP_DEBUG;
    }

    public static function get_instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct() {

        $this->setup_encryption_system();

        $this->options_cache_service = new Services\OptionsCache();
        $this->localization_data_builder = new Services\LocalizationDataBuilder( $this, $this->options_cache_service );
        $this->asset_enqueuer = new Services\AssetEnqueuer( $this, $this->localization_data_builder );
        $this->admin_menu_manager = new Services\AdminMenuManager( $this );
        $this->capability_manager = new Services\CapabilityManager();
        $this->cron_scheduler = new Services\CronScheduler( $this );
        $this->ability_registrar = new Services\AbilityRegistrar( new RestAPIClientFactory() );
        $this->ability_registrar->register();

        $this->fsManager = FsManager::getInstance();
        $this->premiumFeatureManager = PremiumFeatureManager::getInstance();

        $this->init_hooks();
    }

    /**
     * Memory optimization: Clear options cache when needed
     */
    public static function clear_options_cache() {
        $instance = self::get_instance();
        $instance->options_cache_service->clear();
    }

    /**
     * MEMORY OPTIMIZATION: Get cached settings array for Advanced Bulk Generator
     * Prevents repeated option calls and creates settings array once
     *
     * @internal Used by LocalizationDataBuilder service
     */
    public function get_cached_advanced_settings_array() {
        return $this->options_cache_service->getSettingsArray( 'advanced' );
    }

    /**
     * MEMORY OPTIMIZATION: Get cached settings array for Standard Bulk Generator
     * Standard generator has its own separate settings
     *
     * @internal Used by LocalizationDataBuilder service
     */
    public function get_cached_standard_settings_array() {
        return $this->options_cache_service->getSettingsArray( 'standard' );
    }

    /**
     * MEMORY OPTIMIZATION: Get cached settings array for general use (Settings page, etc.)
     * Includes all settings for compatibility
     *
     * @internal Used by LocalizationDataBuilder service
     */
    public function get_cached_settings_array() {
        return $this->options_cache_service->getSettingsArray( 'general' );
    }

    /**
     * Ensure Ctrl module file is loaded
     *
     * @internal Used by LocalizationDataBuilder service
     * @return bool Whether the file was successfully loaded
     */
    public function ensureCtrlModuleFileLoaded() {
        static $ctrl_module_file_loaded = false;
        if ($ctrl_module_file_loaded) {
            return true;
        }

        if (!defined('AIPT_PLUGIN_DIR')) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
            }
            return false;
        }

        $credit_system_path = AIPT_PLUGIN_DIR . 'src/Core/CreditSystem/index.php';
        if (file_exists($credit_system_path)) {
            require_once $credit_system_path;
            $ctrl_module_file_loaded = true;
            return true;
        }
        return false;
    }

    private function getGenerationController() {
        if ( null === $this->generation_controller ) {
            $this->generation_controller = new NewGenerationController();
        }
        return $this->generation_controller;
    }

    private function getContentController() {
        if ( null === $this->content_controller ) {
            $this->content_controller = new ContentController();
        }
        return $this->content_controller;
    }

    private function getStandardBulkGeneratorController() {
        if ($this->standard_bulk_generator_controller === null) {
            $this->standard_bulk_generator_controller = new StandardBulkGeneratorController();
        }
        return $this->standard_bulk_generator_controller;
    }

    private function getTitleGeneratorController() {
        if ($this->title_generator_controller === null) {
            $this->title_generator_controller = new TitleGeneratorController();
        }
        return $this->title_generator_controller;
    }

    private function getFaqGeneratorController() {
        if ($this->faq_generator_controller === null) {
            $this->faq_generator_controller = new FAQGeneratorController();
        }
        return $this->faq_generator_controller;
    }

    private function getSeoMetaGeneratorController() {
        if ($this->seo_meta_generator_controller === null) {
            $this->seo_meta_generator_controller = new SeoMetaGeneratorController();
        }
        return $this->seo_meta_generator_controller;
    }

    private function getTaxonomyGeneratorController() {
        if ($this->taxonomy_generator_controller === null) {
            $this->taxonomy_generator_controller = new TaxonomyGeneratorController();
        }
        return $this->taxonomy_generator_controller;
    }

    /**
     * Get Freemius Manager instance
     *
     * @internal Used by LocalizationDataBuilder service
     * @return FsManager Freemius Manager instance
     */
    public function getFsManager() {
        return $this->fsManager;
    }

    /**
     * Get Premium Feature Manager instance
     *
     * @internal Used by LocalizationDataBuilder service
     * @return PremiumFeatureManager Premium Feature Manager instance
     */
    public function getPremiumFeatureManager() {
        return $this->premiumFeatureManager;
    }

    private function getCustomFields() {
        if ($this->custom_fields === null) {
            $this->custom_fields = new CustomFields();
        }
        return $this->custom_fields;
    }

    private function getCreditRestController() {
        if ($this->credit_rest_controller === null) {
            $this->credit_rest_controller = new CreditRest();
        }
        return $this->credit_rest_controller;
    }

    private function getStoreIndexController() {
        if ($this->store_index_controller === null) {
            $this->store_index_controller = new StoreIndexController();
        }
        return $this->store_index_controller;
    }

    /**
     * Get ChatbotController instance.
     *
     * @return ChatbotController
     */
    private function getChatbotController() {
        if ($this->chatbot_controller === null) {
            $this->chatbot_controller = new ChatbotController();
        }
        return $this->chatbot_controller;
    }

    private function getPromptTemplateController() {
        if ($this->prompt_template_controller === null) {
            $this->prompt_template_controller = new PromptTemplateController();
        }
        return $this->prompt_template_controller;
    }

    private function getPromptBuilderController() {
        if ($this->prompt_builder_controller === null) {
            $registry = new WizardSchemaRegistry();
            $assembler = new PromptAssembler( $registry );

            $this->prompt_builder_controller = new PromptBuilderController( $registry, $assembler );
        }
        return $this->prompt_builder_controller;
    }

    private function getDashboardController() {
        if ($this->dashboard_controller === null) {
            $this->dashboard_controller = new DashboardController();
        }
        return $this->dashboard_controller;
    }

    private function getImageAltController() {
        if ( $this->image_alt_controller === null ) {
            $this->image_alt_controller = new ImageAltController();
        }
        return $this->image_alt_controller;
    }

    private function getUiVariantHealthController() {
        if ( $this->ui_variant_health_controller === null ) {
            $this->ui_variant_health_controller = new UiVariantHealthController(
                new UiVariantService()
            );
        }
        return $this->ui_variant_health_controller;
    }

    private function getUiPrefsController() {
        if ( $this->ui_prefs_controller === null ) {
            $this->ui_prefs_controller = new UiPrefsController();
        }
        return $this->ui_prefs_controller;
    }

    private function getPricingPreviewController() {
        if ( $this->pricing_preview_controller === null ) {
            $this->pricing_preview_controller = new PricingPreviewController();
        }
        return $this->pricing_preview_controller;
    }

    private function init_hooks() {
        add_action('admin_init', [$this, 'handle_activation_redirect']);
        add_action('rest_api_init', [$this, 'register_rest_routes']);
        add_filter('rest_post_dispatch', [$this, 'add_rest_no_cache_headers'], 10, 3);
        add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_Assets']);
        add_action('add_meta_boxes_product', [$this, 'add_product_metabox']);
        add_action('admin_menu', [$this, 'add_admin_menu'], 10);
        add_action('admin_head', [$this, 'add_editor_styles']);
        add_filter('admin_body_class', [$this, 'filter_admin_body_class']);
        add_action('admin_head', [$this, 'print_theme_init_script'], 99);
		add_action( 'update_option_aipt_openai_api_key', [ \AIPT\Utils\ApiKeyManager::class, 'flush_credential_caches' ] );
		add_action( 'add_option_aipt_openai_api_key', [ \AIPT\Utils\ApiKeyManager::class, 'flush_credential_caches' ] );
		add_action( 'update_option_aipt_gemini_api_key', [ \AIPT\Utils\ApiKeyManager::class, 'flush_credential_caches' ] );
		add_action( 'add_option_aipt_gemini_api_key', [ \AIPT\Utils\ApiKeyManager::class, 'flush_credential_caches' ] );
		add_action( 'update_option_aipt_openrouter_api_key', [ \AIPT\Utils\ApiKeyManager::class, 'flush_credential_caches' ] );
		add_action( 'add_option_aipt_openrouter_api_key', [ \AIPT\Utils\ApiKeyManager::class, 'flush_credential_caches' ] );
		add_action( 'update_option_aipt_claude_api_key', [ \AIPT\Utils\ApiKeyManager::class, 'flush_credential_caches' ] );
		add_action( 'add_option_aipt_claude_api_key', [ \AIPT\Utils\ApiKeyManager::class, 'flush_credential_caches' ] );

        add_action('wp_loaded', [$this, 'conditional_credit_check']);

        add_action('init', [$this, 'load_textdomain'], 1);

        add_action('init', [$this, 'initCtrlModule'], 10);

        add_action('init', [$this, 'add_capabilities'], 20);

        add_action('init', ['\AIPT\Utils\ProductFilter\ProductFilterMapper', 'registerCacheInvalidationHooks'], 20);

        add_action('aipt_clean_history_records', ['\AIPT\Core\Database\HistoryCleaner', 'cron_callback']);

        add_action('aipt_clean_job_logs', ['\AIPT\Core\Database\JobLogCleaner', 'cron_callback']);

        add_action('admin_init', ['\AIPT\Core\Database\JobLogCleaner', 'ensure_scheduled']);

        add_action('admin_init', ['\AIPT\Api\StoreIndex\ProfileManager', 'migrateExistingProfilesToIncludeSku']);

        add_action('admin_init', [VariantTelemetryReporter::class, 'reportIfDue']);

        add_action('aipt_cleanup_rate_limits', ['\AIPT\Core\Database\RateLimiterCleaner', 'cron_callback']);

        add_action( \AIPT\Core\Services\PricingFeedManager::CRON_HOOK, ['\AIPT\Core\Services\PricingFeedManager', 'cron_callback'] );

        \AIPT\Core\Database\OrphanCleaner::register();

        add_action('aipt_chatbot_queue_cleanup', [$this, 'cleanup_chatbot_message_queue']);
        add_action('admin_init', [$this, 'schedule_chatbot_queue_cleanup']);
        add_action( ChatbotConstants::ACTION_SCHEDULER_HOOK, [ ChatbotJobWorker::class, 'processJob' ], 10, 1 );
        add_action( ChatbotConstants::STALE_RECOVERY_HOOK, [ ChatbotJobWorker::class, 'reclaimStaleClaims' ], 10, 0 );

        NoticeManager::get_instance();

        add_action( 'wp_ajax_aipt_force_license_reverify', [ \AIPT\Core\Licensing\DirectApiVerifier::class, 'handleForceReverifyAjax' ] );

        add_filter('cron_schedules', [$this, 'add_automation_cron_intervals']);

        add_filter('pre_reschedule_event', [$this, 'prevent_noop_reschedule_race'], 10, 2);
        add_action('aipt_process_automation_jobs', [$this, 'process_automation_jobs']);
        add_action('aipt_monitor_automation_jobs', [$this, 'monitor_automation_jobs']);

        \AIPT\Api\AutomationJobs\JobExecutionHandler::init();

        add_action('wp_loaded', [$this, 'setup_automation_cron_schedules'], 10);

        add_action('aipt_build_store_index', [$this, 'process_store_index_batch'], 10, 5);
        add_action('aipt_scheduled_index_rebuild', [$this, 'trigger_scheduled_index_rebuild'], 10, 1);

        add_action('aipt_store_index_build_complete', [$this, 'clear_store_index_consumer_cache'], 10, 1);

        add_action('wp_enqueue_scripts', [$this, 'enqueue_chatbot_widget_assets']);

        add_action('wp_body_open', [$this, 'render_chatbot_widget_container'], 1);
        add_action('wp_footer', [$this, 'render_chatbot_widget_container'], 10);

		add_action( 'wp_enqueue_scripts', [ FAQFrontendRenderer::class, 'enqueue_styles' ] );
		add_action( 'wp_head', [ FAQFrontendRenderer::class, 'render_dynamic_css' ], 5 );
		add_action( 'woocommerce_after_single_product_summary', [ FAQFrontendRenderer::class, 'render_accordion_content' ], 15 );

		$faq_display_settings = new FAQDisplaySettings();
		$faq_schema_generator = new FAQSchemaGenerator( $faq_display_settings );
		$faq_schema_generator->register_hooks();

		add_action( 'init', [ FAQGeneratorController::class, 'register_meta' ], 20 );

		FAQShortcode::register();

		/**
		 * WP 7.0 AI Connectors integration.
		 *
		 * Activated only when wp_get_connector() exists (WP 7.0+). Warms the
		 * credential resolver for the three core providers (openai/claude/gemini).
		 * The default credential chain (Connectors-first, Local-fallback) can be
		 * customized via the `aipt_credential_provider_chain` filter.
		 *
		 * NOTE: OpenRouter is intentionally NOT registered as a Connector. It
		 * was previously self-registered via OpenRouterConnectorRegistrar but
		 * the registration was removed in 2.6.x because the WP Connectors UI
		 * mis-detected the locally-stored OpenRouter key as Connectors-managed.
		 * OpenRouter now uses the plugin's local AES-256-GCM storage exclusively
		 * (the option key remains `aipt_openrouter_api_key`).
		 *
		 * @since 2.6.0
		 */
		if ( WordPressRuntimeDetector::supportsConnectorsApi() ) {

			CredentialResolver::instance();
		}
    }

    /**
     * MEMORY OPTIMIZATION: Only run credit check on specific pages
     * Uses wp_loaded hook for better performance than admin_init
     */
    public function conditional_credit_check() {

        if (!is_admin()) {
            return;
        }

        $current_page = isset($_GET['page']) ? sanitize_text_field(wp_unslash($_GET['page'])) : '';
        if ($current_page !== 'aipt-advanced-bulk-generator') {
            return;
        }

        $this->check_credits_renewal();
    }

    public function add_capabilities() {

        $this->capability_manager->registerCapabilities();
    }

    public function register_rest_routes() {
        $endpoints = new RestEndpoints();
        $endpoints->register_routes();

        $this->getGenerationController()->register_routes();
        $this->getContentController()->register_routes();

        $this->getStandardBulkGeneratorController()->register_routes();
        $this->getTitleGeneratorController()->register_routes();
        $this->getFaqGeneratorController()->register_routes();
        $this->getSeoMetaGeneratorController()->register_routes();
        $this->getTaxonomyGeneratorController()->register_routes();
        $this->getCustomFields()->register_routes();
        $this->getCreditRestController()->register();
        $this->getStoreIndexController()->register_routes();
        $this->getChatbotController()->register_routes();
        $this->getPromptTemplateController()->register_routes();
        $this->getPromptBuilderController()->register_routes();
        $this->getDashboardController()->register_routes();
        $this->getImageAltController()->register_routes();
		$this->getUiVariantHealthController()->register_routes();
		$this->getUiPrefsController()->register_routes();
		$this->getPricingPreviewController()->register_routes();

		( new FAQDisplaySettingsController() )->register_routes();
    }

    /**
     * Add no-cache headers to all AIPT REST API responses.
     *
     * Prevents server-level caching (LiteSpeed, Cloudflare, reverse proxies)
     * from returning stale data for dynamic plugin endpoints.
     * This fixes issues on some hosting environments where GET responses
     * are cached, causing stale job lists, stuck build progress, and
     * outdated credit balances.
     *
     * @param \WP_REST_Response $response The response object.
     * @param \WP_REST_Server   $server   The REST server instance.
     * @param \WP_REST_Request  $request  The request object.
     * @return \WP_REST_Response Modified response with cache-busting headers.
     */
    public function add_rest_no_cache_headers($response, $server, $request) {
        $route = $request->get_route();

        $is_aipt_route = strpos($route, '/aipt/') !== false;

        if ($is_aipt_route) {
            $response->header('Cache-Control', 'no-cache, no-store, must-revalidate');
            $response->header('Pragma', 'no-cache');
            $response->header('Expires', '0');
        }

        return $response;
    }

    /**
     * Convert WordPress locale format to standard format
     *
     * @internal Used by LocalizationDataBuilder service
     * @param string $wp_locale WordPress locale (e.g., 'en_US')
     * @return string Standard locale format (e.g., 'en-US')
     */
    public function convert_locale_format($wp_locale) {
        return str_replace('_', '-', $wp_locale);
    }

    public function enqueue_admin_Assets($hook) {

        $this->asset_enqueuer->enqueueForHook( $hook );
    }

    private function get_faq_localized_data(): array {
        $defaults = [
            'faqCount' => FAQGeneratorService::DEFAULT_FAQ_COUNT,
            'faqFormat' => self::get_default_faq_format(),
            'faqMode' => self::get_default_faq_mode(),
            'writeMode' => 'append',
            'targetField' => 'post_content',
        ];

        return [
            'restUrl' => esc_url_raw(rest_url()),
            'restNonce' => wp_create_nonce('wp_rest'),
            'adminUrl' => admin_url(),
            'faqDefaults' => $defaults,
            'maxFaqCount' => FAQGeneratorService::MAX_FAQ_COUNT,
            'customFieldsEndpoint' => esc_url_raw(rest_url('aipt/v1/custom-fields')),
        ];
    }

    public static function get_default_faq_format(): string {
        return 'text';
    }

    public static function get_default_faq_mode(): string {
        return 'both';
    }

    /**
     * Get asset path with dist prefix
     *
     * @internal Used by AssetEnqueuer service
     * @param string $path Asset yolu (örn: 'css/commons.css')
     * @return string Tam asset yolu (örn: 'dist/css/commons.css')
     */
    public function get_asset_path($path) {
        return 'dist/' . $path;
    }

    public function add_product_metabox() {

        $metabox_hidden = get_option( 'aipt_metabox_hidden', Activator::get_default_value( 'metabox_hidden' ) );
        if ( $metabox_hidden ) {
            return;
        }

        add_meta_box(
            'aipt_product_metabox',
            __('AI Product Tools', 'ai-product-tools'),
            [$this, 'render_product_metabox'],
            'product',
            'side',
            'high'
        );
    }

    public function render_product_metabox($post) {

        echo '<style>#aipt_product_metabox .hndle, #aipt_product_metabox .handle-actions { display: none !important; } #aipt_product_metabox .inside { margin: 0 !important; padding: 0 !important; }</style>';
        echo '<div id="aipt-metabox-root" class="aipt-ui-shell"></div>';
    }

    /**
     * Get onboarding status quickly without API call
     * This is optimized for fast loading
     *
     * @internal Used by LocalizationDataBuilder service
     * @return array Onboarding status data
     */
    public function get_onboarding_status_fast(): array {
        try {

            $has_api_key = false;
            if (class_exists('\AIPT\Utils\ApiKeyManager')) {
                $has_api_key = \AIPT\Utils\ApiKeyManager::has_any_api_key();
            }

            $setup_completed = get_option('aipt_setup_completed', false);

            $onboarding_dismissed = get_option('aipt_onboarding_dismissed', false);

            $snooze_until = get_option('aipt_onboarding_snoozed_until', 0);
            $is_snoozed = $snooze_until > time();

            $should_show = !$has_api_key && !$setup_completed && !$onboarding_dismissed && !$is_snoozed;

            $qs_completed_steps = get_option( 'aipt_quickstart_completed_steps', '[]' );
            if ( is_string( $qs_completed_steps ) ) {
                $qs_completed_steps = json_decode( $qs_completed_steps, true );
                if ( ! is_array( $qs_completed_steps ) ) {
                    $qs_completed_steps = [];
                }
            }

            return [
                'shouldShow' => $should_show,
                'isFirstTime' => !get_option('aipt_first_run_completed', false),
                'hasApiKey' => $has_api_key,
                'setupCompleted' => $setup_completed,
                'onboardingDismissed' => $onboarding_dismissed,
                'isSnoozed' => $is_snoozed,
                'snoozeUntil' => $snooze_until,
                'quickstart' => [
                    'completedSteps' => array_values( $qs_completed_steps ),
                    'dismissed'      => (bool) get_option( 'aipt_quickstart_dismissed', false ),
                    'completed'      => (bool) get_option( 'aipt_quickstart_completed', false ),
                    'totalSteps'     => 4,
                ],
            ];
        } catch (\Exception $e) {

            return [
                'shouldShow' => false,
                'isFirstTime' => false,
                'hasApiKey' => true, 
                'setupCompleted' => true,
                'onboardingDismissed' => true
            ];
        }
    }

    

    public function add_admin_menu() {

        $this->admin_menu_manager->registerMenus();
    }

    /**
     * Setup encryption system for new installations
     * Ensures API keys are stored encrypted from first use
     */
    private function setup_encryption_system() {
        static $setup_attempted = false;

        if (!$setup_attempted) {
            $setup_attempted = true;

            try {

                Encryption::setup_new_installation();

                if (!\AIPT\Utils\Encryption::is_migration_completed()) {
                    \AIPT\Utils\ApiKeyManager::migrate_keys_if_needed();
                }

            } catch (\Exception $e) {
            }
        }
    }

    private function hasApiKeys(): bool {

        return \AIPT\Utils\ApiKeyManager::has_any_api_key();
    }

    public function render_toolkit_page() {

        $this->admin_menu_manager->renderToolkitPage();
    }

    public function render_settings_page() {

        $this->admin_menu_manager->renderSettingsPage();
    }

    public function render_bulk_generator_page() {

        $this->admin_menu_manager->renderBulkGeneratorPage();
    }

    public function render_standard_bulk_generator_page() {

        $this->admin_menu_manager->renderStandardBulkGeneratorPage();
    }

    public function render_faq_generator_page() {

        $this->admin_menu_manager->renderFaqGeneratorPage();
    }

    public function render_title_generator_page() {

        $this->admin_menu_manager->renderTitleGeneratorPage();
    }

    public function render_automation_jobs_page() {

        $this->admin_menu_manager->renderAutomationJobsPage();
    }

    public function add_editor_styles() {
        if (!function_exists('get_current_screen')) {
            return;
        }

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

    /**
     * Add scoped Tailwind wrapper classes to admin body on plugin pages
     *
     * @param string $classes Existing admin body classes.
     * @return string
     */
    public function filter_admin_body_class($classes) {
        if (!function_exists('get_current_screen')) {
            return $classes;
        }

        $screen = get_current_screen();
        if (!$screen) {
            return $classes;
        }

        $is_product_editor = (
            isset($screen->post_type) &&
            'product' === $screen->post_type &&
            isset($screen->base) &&
            in_array($screen->base, ['post', 'post-new'], true)
        );

        if ($is_product_editor) {
            return $classes;
        }

        $screen_id = isset($screen->id) ? (string) $screen->id : '';

        $is_aipt_admin_page = (
            $screen_id !== '' &&
            (strpos($screen_id, 'ai-product-tools') !== false ||
            strpos($screen_id, 'aipt-') !== false)
        );

        if ($is_aipt_admin_page) {
            $classes .= ' aipt-ui-shell';
        }

        return $classes;
    }

    /**
     * Print inline script in admin <head> for zero-flash theme detection.
     *
     * Reads the user's explicit theme choice from localStorage and sets
     * a data attribute on <html> before <body> renders. This ensures CSS
     * selectors (html[data-aipt-theme="dark"]) are active before first paint.
     * If no explicit choice exists, CSS @media (prefers-color-scheme) handles it.
     */
    public function print_theme_init_script() {
        if (!function_exists('get_current_screen')) {
            return;
        }

        $screen = get_current_screen();
        if (!$screen) {
            return;
        }

        $screen_id = isset($screen->id) ? (string) $screen->id : '';

        $is_aipt_page = (
            $screen_id !== '' &&
            (strpos($screen_id, 'ai-product-tools') !== false ||
            strpos($screen_id, 'aipt-') !== false)
        );

        $is_product_editor = (
            isset($screen->post_type) &&
            'product' === $screen->post_type &&
            isset($screen->base) &&
            in_array($screen->base, ['post', 'post-new'], true)
        );

        if (!$is_aipt_page && !$is_product_editor) {
            return;
        }

        echo '<script id="aipt-theme-init">', '(function(){var d="light";try{var t=localStorage.getItem("aipt-theme");if(t==="dark"||t==="light"){d=t;}}catch(e){}document.documentElement.dataset.aiptTheme=d;})()', '</script>';
    }

    /**
     * Check credit balance on Advanced Bulk Generator page
     * Only runs on Advanced Bulk Generator page for pre-loading balance
     */
    public function check_credits_renewal() {
        $this->ensureCtrlModuleFileLoaded();

        $current_page = isset($_GET['page']) ? sanitize_text_field(wp_unslash($_GET['page'])) : '';

        if ($current_page !== 'aipt-advanced-bulk-generator') {
            return;
        }

        \AIPT\Core\CreditSystem\CreditManager::getInstance()->getBalance();
    }

    /**
     * Initialize Credit System module
     *
     * @return void
     */
    /**
     * Load plugin text domain for translations.
     *
     * @since 2.5.12
     * @return void
     */
    public function load_textdomain() {
        load_plugin_textdomain(
            'ai-product-tools',
            false,
            basename( AIPT_PLUGIN_DIR ) . '/languages'
        );
    }

    public function initCtrlModule() {

        if (did_action('aipt_ctrl_module_initialized')) {
            return;
        }

        require_once AIPT_PLUGIN_DIR . 'src/Core/CreditSystem/index.php';

        \AIPT\Core\CreditSystem\setupCreditSystem();

        do_action('aipt_ctrl_module_initialized');
    }

    public function handle_activation_redirect() {

        if (!is_admin() || !current_user_can('manage_options')) {
            return;
        }

        if (get_transient('aipt_activation_redirect')) {
            delete_transient('aipt_activation_redirect');
            if (!headers_sent()) {
                wp_safe_redirect(admin_url('admin.php?page=ai-product-tools'));
                exit;
            }
        }
    }

    public function add_automation_cron_intervals($schedules) {

        return $this->cron_scheduler->addAutomationIntervals( $schedules );
    }

    /**
     * pre_reschedule_event filter callback (@since 2.6.2).
     *
     * Thin delegation to CronScheduler — see preventNoopRescheduleRace() there
     * for the full rationale (suppress could_not_set noise from no-op
     * reschedule races for our two recurring hooks).
     *
     * @param null|bool|\WP_Error $pre   Prior filter result.
     * @param object              $event WP cron event object.
     * @return null|bool|\WP_Error       Filter result.
     */
    public function prevent_noop_reschedule_race($pre, $event) {
        return $this->cron_scheduler->preventNoopRescheduleRace( $pre, $event );
    }

    public function process_automation_jobs() {

        $this->cron_scheduler->processAutomationJobs();
    }

    public function monitor_automation_jobs() {

        $this->cron_scheduler->monitorAutomationJobs();
    }

    public function setup_automation_cron_schedules() {

        $this->cron_scheduler->setupAutomationSchedules();
    }

    /**
     * Register and enqueue a virtual style handle that depends on shared assets.
     *
     * @internal Used by LocalizationDataBuilder service
     * @param string $handle Style handle to register.
     * @param array  $dependencies Optional dependency handles.
     */
    public function enqueue_virtual_style( string $handle, array $dependencies = [] ) : void {
        if ( ! wp_style_is( $handle, 'registered' ) ) {
            wp_register_style(
                $handle,
                false,
                array_unique( $dependencies ),
                AIPT_VERSION
            );
        }

        wp_enqueue_style( $handle );
    }

    /**
     * Process a batch of products for the AI Store Index.
     *
     * Callback for Action Scheduler hook 'aipt_build_store_index'.
     *
     * @param int $profile_id      Profile ID for multi-profile support.
     * @param int $job_id          Job identifier.
     * @param int $last_id         Last processed product ID (keyset pagination).
     * @param int $batch_size      Number of products per batch.
     * @param int $processed_count Total products processed so far.
     */
    public function process_store_index_batch(int $profile_id, int $job_id, int $last_id, int $batch_size, int $processed_count = 0): void {
        $builder = new IndexBuilder($profile_id);
        $builder->processBatch($job_id, $last_id, $batch_size, $processed_count);
    }

    /**
     * Trigger scheduled index rebuild.
     *
     * Callback for Action Scheduler hook 'aipt_scheduled_index_rebuild'.
     *
     * @param int $profile_id Profile ID for multi-profile support (defaults to active profile).
     */
    public function trigger_scheduled_index_rebuild(int $profile_id = 0): void {
        $builder = new IndexBuilder($profile_id);

        $settings = new IndexSettings($profile_id ?: $builder->getProfileId());

        if ($settings->isEnabled()) {
            try {
                $builder->start(false);
            } catch (\Exception $e) {
            }
        }
    }

    /**
     * Clear IndexConsumer cache when build completes.
     *
     * Ensures consumers get fresh data after rebuild.
     *
     * @param array $meta Build metadata containing profile_id.
     */
    public function clear_store_index_consumer_cache( array $meta = array() ): void {
        $profile_id = isset( $meta['profile_id'] ) ? (int) $meta['profile_id'] : 1;
        $consumer   = new \AIPT\Api\StoreIndex\IndexConsumer( $profile_id );
        $consumer->clearCache();
    }

    /**
     * Schedule chatbot message queue cleanup cron.
     *
     * Uses a transient guard to prevent repeated wp_next_scheduled() checks
     * on every admin page load, improving performance.
     *
     * @since 2.5.0
     */
    public function schedule_chatbot_queue_cleanup(): void {

        if ( get_transient( 'aipt_chatbot_cron_checked' ) ) {
            return;
        }
        set_transient( 'aipt_chatbot_cron_checked', true, HOUR_IN_SECONDS );

        if ( ! wp_next_scheduled( 'aipt_chatbot_queue_cleanup' ) ) {
            wp_schedule_event( time(), 'daily', 'aipt_chatbot_queue_cleanup' );
        }
    }

    /**
     * Clean up old chatbot message queue records.
     *
     * Called by cron to remove messages older than 30 days.
     *
     * @since 2.5.0
     */
    public function cleanup_chatbot_message_queue(): void {
        $message_queue = new \AIPT\Api\Chatbot\MessageQueue();
        $deleted = $message_queue->cleanup(30);

        if ($deleted > 0) {
        }
    }

    /**
     * Enqueue chatbot widget assets on frontend.
     *
     * @since 2.5.0
     */
    public function enqueue_chatbot_widget_assets(): void {

        if (is_admin()) {
            return;
        }

        $asset_enqueuer = $this->asset_enqueuer;
        if ( null === $asset_enqueuer ) {
            $options_cache = $this->options_cache_service ?? new Services\OptionsCache();
            $data_builder = $this->localization_data_builder ?? new Services\LocalizationDataBuilder( $this, $options_cache );
            $asset_enqueuer = new Services\AssetEnqueuer( $this, $data_builder );
        }

        $asset_enqueuer->enqueueChatbotWidgetAssets();
    }

    /**
     * Render chatbot widget container.
     *
     * Registered on both wp_body_open (primary) and wp_footer (fallback).
     * Uses wp_body_open when available to avoid output buffering issues
     * caused by caching plugins (e.g., Kinsta, LiteSpeed).
     * Falls back to wp_footer for themes that don't call wp_body_open().
     *
     * @since 2.5.0
     */
    public function render_chatbot_widget_container(): void {

        if ($this->chatbot_container_rendered) {
            return;
        }

        if (is_admin()) {
            return;
        }

        $settings = get_option('aipt_chatbot_settings', []);
        $is_enabled = isset($settings['general']['enabled']) ? (bool) $settings['general']['enabled'] : false;

        if (!$is_enabled) {
            return;
        }

        if (!$this->should_show_chatbot_on_page($settings)) {
            return;
        }

        echo '<div id="aipt-chatbot-widget-root"></div>';

        $this->chatbot_container_rendered = true;
    }

    /**
     * Check if chatbot should be shown on current page.
     *
     * @since 2.5.0
     * @param array $settings Chatbot settings.
     * @return bool True if should show.
     */
    public function should_show_chatbot_on_page(array $settings): bool {
        $placement = $settings['placement'] ?? [];

        $excluded_types = $placement['excluded_page_types'] ?? [];
        if (in_array('checkout', $excluded_types, true) && function_exists('is_checkout') && is_checkout()) {
            return false;
        }
        if (in_array('cart', $excluded_types, true) && function_exists('is_cart') && is_cart()) {
            return false;
        }
        if (in_array('my-account', $excluded_types, true) && function_exists('is_account_page') && is_account_page()) {
            return false;
        }

        $visibility_mode = $placement['visibility_mode'] ?? 'all';
        $current_page_id = get_queried_object_id();

        if ($visibility_mode === 'specific') {
            $specific_pages = $placement['specific_pages'] ?? [];

            $specific_pages_int = array_map( 'intval', $specific_pages );
            if (!empty($specific_pages_int) && !in_array($current_page_id, $specific_pages_int, true)) {
                return false;
            }
        } elseif ($visibility_mode === 'exclude') {
            $excluded_pages = $placement['excluded_pages'] ?? [];

            $excluded_pages_int = array_map( 'intval', $excluded_pages );
            if (!empty($excluded_pages_int) && in_array($current_page_id, $excluded_pages_int, true)) {
                return false;
            }
        }

        return true;
    }
}
