<?php

namespace Licenzo\Framework\Asset;

use Licenzo\App;

class Vite
{
    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::$devServer    = App::config('app.vite.dev_server', 'http://localhost:3000');
        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(),
                true
            );

            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;
        }

        // Load imported chunks (vendor files) first
        if (!empty($manifest[$entry]['imports'])) {
            foreach ($manifest[$entry]['imports'] as $index => $importKey) {
                if (isset($manifest[$importKey])) {
                    $importFile = $manifest[$importKey]['file'] ?? null;

                    if ($importFile && file_exists(static::$pluginDir . '/assets/' . $importFile)) {
                        $importHandle = $handle . '-import-' . $index;

                        wp_enqueue_script(
                            $importHandle,
                            static::getProdAssetURL($importFile),
                            [],
                            static::getVersion(),
                            $inFooter
                        );

                        static::markAsModule($importHandle);

                        // Add import as dependency for main entry
                        $deps[] = $importHandle;
                    }
                }
            }
        }

        // Load main entry file (now depends on imports)
        $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 from entry
        if (!empty($manifest[$entry]['css'])) {
            foreach ($manifest[$entry]['css'] as $i => $cssFile) {
                wp_enqueue_style(
                    $handle . '-style-' . $i,
                    static::$pluginUrl . '/assets/' . $cssFile,
                    [],
                    static::getVersion(),
                );
            }
        }

        // Also load CSS from imported chunks
        if (!empty($manifest[$entry]['imports'])) {
            foreach ($manifest[$entry]['imports'] as $index => $importKey) {
                if (isset($manifest[$importKey]['css'])) {
                    foreach ($manifest[$importKey]['css'] as $i => $cssFile) {
                        wp_enqueue_style(
                            $handle . '-import-' . $index . '-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);

        if ($ch) {
            fclose($ch);
            return true;
        }
        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 = '';
        global $wp_filesystem;
        if (empty($wp_filesystem)) {
            require_once ABSPATH . '/wp-admin/includes/file.php';
            WP_Filesystem();
        }
        if ($wp_filesystem) {
            $content = $wp_filesystem->get_contents($manifestPath);
        } else {
            $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(LICENZO_PLUGIN_URL, LICENZO_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';
    }
}
