<?php

declare(strict_types=1);

namespace FleekDash\Admin;

use FleekDash\Core\ScriptHandles;
use FleekDash\Libs\Assets as AssetsLib;
use FleekDash\Realtime\RealtimeConfig;

// Load debug helpers
if (!function_exists('fleekdash_log_error')) {
    require_once FLEEKDASH_PLUGIN_DIR . 'includes/Core/debug-helpers.php';
}

/**
 * Handles script enqueue logic for FleekDash admin (dev/production, fallback, vendor chunks).
 *
 * @package FleekDash\Admin
 */
class AssetsEnqueueHelper
{
    private const JS_WINDOW_FLEEKDASH_ASSIGN_PREFIX = 'window.FleekDash = Object.assign({}, window.FleekDash || {}, ';

    private Assets $assets;

    /**
     * Constructor
     *
     * @param Assets $assets Parent Assets instance
     */
    public function __construct(Assets $assets)
    {
        $this->assets = $assets;
    }

    /**
     * Check if current environment is development (delegates to Assets)
     *
     * @return bool
     */
    private function isDevelopmentEnvironment(): bool
    {
        return $this->assets->isDevelopmentEnvironment();
    }

    /**
     * Set script type as module (delegates to Assets)
     *
     * @param string $handle Script handle
     */
    private function setScriptTypeModule(string $handle): void
    {
        $this->assets->setScriptTypeModule($handle);
    }

    /**
     * Add defer attribute to script (delegates to Assets)
     *
     * @param string $handle Script handle
     */
    private function addDeferAttribute(string $handle): void
    {
        $this->assets->addDeferAttribute($handle);
    }

    /**
     * Deregister WordPress React on FleekDash pages and optionally add React Scan.
     */
    public function deregisterWordPressReactOnFleekDash(bool $is_fleekdash_page): void
    {
        if (!$is_fleekdash_page) {
            return;
        }

        foreach (ScriptHandles::WORDPRESS_REACT as $handle) {
            \wp_deregister_script($handle);
        }

        \add_action('admin_head', [$this->assets, 'addReactScanScript'], -1);
    }

    /**
     * Lightweight window.FleekDash for wp-admin screens that do not mount the React shell.
     *
     * Loading the full Vite/React bundle on every admin screen amplifies failures from third-party
     * plugins (broken scripts, exhausted connections, TDZ across chunks). Classic WordPress stays
     * usable — plugin helper scripts still read FleekDash.debug via optional chaining.
     */
    public function injectMinimalClassicAdminBootstrap(): void
    {
        static $injected = false;
        if ($injected) {
            return;
        }
        $injected = true;
        $payload = $this->assets->getClassicAdminHeadBootstrapData();
        \add_action(
            'admin_head',
            static function () use ($payload): void {
                echo '<script>';
                echo self::JS_WINDOW_FLEEKDASH_ASSIGN_PREFIX;
                echo \wp_json_encode($payload) . ');';
                echo '</script>';
            },
            0,
        );
    }

    /**
     * Enqueue theme shortcut and classic mode persistence scripts.
     */
    public function enqueueCommonAdminScripts(): void
    {
        \wp_enqueue_script(
            'fleekdash-theme-shortcut',
            \FleekDash\Libs\Assets\getJsUrl('theme-shortcut'),
            array(),
            FLEEKDASH_VERSION,
            true,
        );
        $this->addDeferAttribute('fleekdash-theme-shortcut');

        \wp_enqueue_script(
            'fleekdash-classic-mode-persistence',
            \FleekDash\Libs\Assets\getJsUrl('classic-mode-persistence'),
            array(),
            FLEEKDASH_VERSION,
            true,
        );
        $this->addDeferAttribute('fleekdash-classic-mode-persistence');
    }

    /**
     * Enqueue main script (dev or production).
     *
     * Dev URLs come from assets/vite-dev-server.json (written by @kucrut/vite-for-wp on `pnpm dev`),
     * so HMR works when Vite picks a port other than the default 5174.
     */
    public function enqueueMainScript(bool $is_fleekdash_page): void
    {
        $result = AssetsLib\enqueueAsset(
            FLEEKDASH_DIR . '/assets',
            Assets::DEV_SCRIPT,
            $this->assets->getConfig(),
        );

        if (!$result && $is_fleekdash_page && !$this->isDevelopmentEnvironment()) {
            $this->enqueueProductionFallback();
        }
    }

    /**
     * Fallback when production asset enqueue fails.
     */
    public function enqueueProductionFallback(): void
    {
        fleekdash_log_error('FleekDash: WARNING - Failed to enqueue production assets! Trying fallback method.');

        $admin_dir = FLEEKDASH_DIR . '/assets/admin';
        if (!is_dir($admin_dir)) {
            fleekdash_log_error('FleekDash: Admin directory not found!');
            return;
        }

        $js_files = glob($admin_dir . '/*.js');
        if (empty($js_files)) {
            fleekdash_log_error('FleekDash: No JS files found in admin directory!');
            return;
        }

        $js_file = $js_files[0];
        $js_url = plugins_url('assets/admin/' . basename($js_file), FLEEKDASH_PLUGIN_FILE);
        fleekdash_log_info('FleekDash: Using fallback JS file: ' . $js_url);

        \wp_register_script(Assets::HANDLE, $js_url, [], FLEEKDASH_VERSION, true);
        $this->setScriptTypeModule(Assets::HANDLE);
        \wp_enqueue_script(Assets::HANDLE);
        $this->addDeferAttribute(Assets::HANDLE);

        $this->enqueueVendorChunks($admin_dir);
    }

    /**
     * Enqueue vendor chunk scripts.
     */
    public function enqueueVendorChunks(string $admin_dir): void
    {
        $chunks = ['vendor-react', 'vendor-motion', 'vendor-iconify', 'components', 'theme'];

        foreach ($chunks as $chunk) {
            $chunk_files = glob($admin_dir . '/' . $chunk . '.*.js');
            if (empty($chunk_files)) {
                continue;
            }
            $chunk_file = $chunk_files[0];
            $chunk_url = plugins_url('assets/admin/' . basename($chunk_file), FLEEKDASH_PLUGIN_FILE);
            $chunk_handle = Assets::HANDLE . '-' . $chunk;

            \wp_register_script($chunk_handle, $chunk_url, [Assets::HANDLE], FLEEKDASH_VERSION, true);
            $this->setScriptTypeModule($chunk_handle);
            \wp_enqueue_script($chunk_handle);
            $this->addDeferAttribute($chunk_handle);
        }
    }

    /**
     * Localize FleekDash script (initial + late backup).
     */
    public function localizeFleekDashScript(): void
    {
        static $script_localized = false;

        if ($script_localized) {
            return;
        }

        $data = $this->mergeFleekDashLocalizationData($this->assets->getData());
        $this->registerAdminHeadFleekDashBootstrap($data);
        $script_localized = true;
        $this->registerLateFooterFleekDashLocalizationBackup();
    }

    /**
     * @param array<string, mixed> $data
     *
     * @return array<string, mixed>
     */
    private function mergeFleekDashLocalizationData(array $data): array
    {
        if (class_exists('\FleekDash\Core\I18nManager')) {
            $i18n_manager = \FleekDash\Core\I18nManager::getInstance();
            $data['i18n'] = $i18n_manager->getLocaleData();
        }
        if (class_exists('\FleekDash\Core\FeaturesManager')) {
            \FleekDash\Core\FeaturesManager::getInstance();
        }
        if (class_exists('\FleekDash\Realtime\RealtimeConfig')) {
            $data['realtime'] = $this->buildRealtimeWindowPayload();
        }

        return $data;
    }

    /**
     * @return array<string, mixed>
     */
    private function buildRealtimeWindowPayload(): array
    {
        $current_user_id = (int) \get_current_user_id();
        $provider = RealtimeConfig::getProvider();
        $transport = $provider === 'managed' ? 'supabase' : 'websocket';
        $supabase_url = defined('FLEEKDASH_SUPABASE_URL') ? (string) \FLEEKDASH_SUPABASE_URL : '';
        $supabase_anon = defined('FLEEKDASH_SUPABASE_KEY') ? (string) \FLEEKDASH_SUPABASE_KEY : '';

        return [
            'enabled' => RealtimeConfig::isEnabled(),
            'transport' => $transport,
            'url' => $provider === 'managed' ? '' : RealtimeConfig::getWsUrl(),
            'supabaseUrl' => $supabase_url,
            'supabaseAnonKey' => $supabase_anon,
            'token' => $current_user_id > 0 ? \wp_create_nonce('fleekdash_realtime_' . $current_user_id) : '',
            'tenantId' => RealtimeConfig::getTenantId(),
            'userId' => $current_user_id,
            'maxSubscriptionsPerClient' => RealtimeConfig::getMaxSubscriptionsPerClient(),
            'maxPayloadBytes' => RealtimeConfig::getMaxPayloadBytes(),
            'killSwitch' => RealtimeConfig::isKillSwitchEnabled(),
            'rolloutCohort' => RealtimeConfig::getRolloutCohort(),
        ];
    }

    /**
     * @param array<string, mixed> $data
     */
    private function registerAdminHeadFleekDashBootstrap(array $data): void
    {
        \add_action(
            'admin_head',
            static function () use ($data): void {
                echo '<script>';
                echo self::JS_WINDOW_FLEEKDASH_ASSIGN_PREFIX . \wp_json_encode($data) . ');';
                echo 'if (window.FleekDash.i18n) { window.fleekDashI18n = window.FleekDash.i18n; }';
                echo '</script>';
            },
            0,
        );
    }

    private function registerLateFooterFleekDashLocalizationBackup(): void
    {
        \add_action(
            'admin_print_footer_scripts',
            function (): void {
                static $late_localization_attempted = false;
                if ($late_localization_attempted || \wp_script_is(Assets::HANDLE, 'data')) {
                    return;
                }
                $late_localization_attempted = true;
                $data = $this->assets->getData();
                echo '<script>';
                echo self::JS_WINDOW_FLEEKDASH_ASSIGN_PREFIX . \wp_json_encode($data) . ');';
                echo '</script>';
            },
            20,
        );
    }
}
