<?php

namespace ZenoChatbot\Framework\Asset;

use ZenoChatbot\App;

class Vite
{
    /** Max seconds to wait when probing the Vite dev server. */
    private const DEV_PROBE_TIMEOUT = 1.0;

    private static string $pluginUrl;
    private static string $pluginDir;
    private static string $manifestPath;
    private static $manifest = [];
    private static string $devServer = 'http://localhost:3000';
    private static bool $isDev = false;

    public function __construct($pluginUrl, $pluginDir)
    {
        static::$pluginUrl    = rtrim($pluginUrl, '/');
        static::$pluginDir    = rtrim($pluginDir, '/');
        static::$manifestPath = App::config('app.vite.manifest_path');
        static::$isDev        = static::isDevServerRunning();
    }

    /**
     * Enqueue a Vite entrypoint.
     */
    public static function enqueue($handle, $entry, $deps = [], $inFooter = true): void
    {
        static::create();

        if (static::isDev()) {
            // Inject Vite HMR client
            wp_enqueue_script(
                'vite-client',
                static::$devServer . '/@vite/client',
                [],
                time(),
                [],
            );

            static::markAsModule('vite-client');

            // Load entry from dev server
            wp_enqueue_script(
                $handle,
                static::getDevAssetURL($entry),
                $deps,
                time(),
                $inFooter
            );

            static::markAsModule($handle);

            return;
        }

        $manifest = static::getManifest();

        if (!isset($manifest[$entry])) {
            trigger_error("Vite manifest entry not found: {$entry}", E_USER_WARNING);
            return;
        }

        $file = $manifest[$entry]['file'] ?? null;

        if ($file && file_exists(static::$pluginDir . '/assets/' . $file)) {

            wp_enqueue_script(
                $handle,
                static::getProdAssetURL($file),
                $deps,
                static::getVersion(),
                $inFooter
            );

            static::markAsModule($handle);
        }

        // Handle CSS imports
        if (!empty($manifest[$entry]['css'])) {

            foreach ($manifest[$entry]['css'] as $i => $cssFile) {

                wp_enqueue_style(
                    $handle . '-style-' . $i,
                    static::$pluginUrl . '/assets/' . $cssFile,
                    [],
                    static::getVersion(),
                );
            }
        }
    }

    /**
     * Check if Vite dev server is running.
     */
    private static function isDevServerRunning()
    {

        if(App::config('app.mode') === 'prod') {
            return false;
        }

        $host = parse_url(static::$devServer, PHP_URL_HOST);
        $port = parse_url(static::$devServer, PHP_URL_PORT);

        $ch = @fsockopen($host, $port, $errno, $errstr, static::DEV_PROBE_TIMEOUT);

        if ($ch) {
            fclose($ch);
            return true;
        }

        // The @-suppressed connect warning still populates error_get_last(),
        // which makes wp-admin append the `php-error` body class. Clear it.
        error_clear_last();

        return false;
    }

    /**
     * Load and parse manifest.json.
     */
    private static function getManifest()
    {
        if (!empty(static::$manifest)) {
            return static::$manifest;
        }

        $manifestPath = static::$pluginDir . '/' . ltrim(static::$manifestPath, '/');

        if (!file_exists($manifestPath)) {
            trigger_error("Vite manifest not found: {$manifestPath}", E_USER_WARNING);
            return [];
        }

        $content = file_get_contents($manifestPath);
        static::$manifest = json_decode($content, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            trigger_error('Invalid JSON in manifest: ' . json_last_error_msg(), E_USER_WARNING);
            return [];
        }

        return static::$manifest;
    }

    public static function create()
    {
        return new self(ZENOCHATBOT_PLUGIN_URL, ZENOCHATBOT_PLUGIN_DIR);
    }

    private static function markAsModule($handle)
    {
        add_filter('script_loader_tag', function ($tag, $tagHandle, $src) use ($handle) {

            if ($tagHandle === $handle) {
                return str_replace('<script ', '<script type="module" ', $tag);
            }

            return $tag;

        }, 10, 3);
    }

    public static function getDevAssetURL($handle)
    {
        return static::$devServer . '/' . ltrim($handle, '/');
    }

    public static function getProdAssetURL($handle)
    {
        return static::$pluginUrl . '/assets/' . ltrim($handle, '/');
    }

    public static function getVersion()
    {
        if(static::$isDev) {
            return time();
        }

        return App::config('app.version') ?? '1.0.0';
    }

    public static function isDev()
    {
        return App::config('app.mode') === 'dev';
    }
}
