<?php

namespace FleekDash\Integrations\Core;

defined('ABSPATH') || exit;

/**
 * Shared components manager for the MU plugin integration system.
 *
 * Manages shared UI assets that can be used by integrations built as dynamic MU plugins.
 */
class SharedComponentsManager
{
    private static ?self $instance = null;
    private array $registeredComponents = [];
    private bool $assetsEnqueued = false;

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

    private function __construct()
    {
        $this->registerCoreComponents();

        // Hook early so shared assets are available to MU plugins
        add_action('muplugins_loaded', [$this, 'initializeSharedAssets'], 1);
        add_action('wp_enqueue_scripts', [$this, 'enqueueSharedAssets'], 5);
        add_action('admin_enqueue_scripts', [$this, 'enqueueSharedAssets'], 5);
    }

    /**
     * Register core FleekDash components for sharing.
     */
    private function registerCoreComponents(): void
    {
        $this->registeredComponents = [
            // Basic UI building blocks
            'card' => [
                'name' => 'Card',
                'css_handle' => 'fleekdash-shared-card',
                'js_handle' => 'fleekdash-shared-ui',
                'dependencies' => ['vendor-ui']
            ],
            'input' => [
                'name' => 'Input',
                'css_handle' => 'fleekdash-shared-input',
                'js_handle' => 'fleekdash-shared-ui',
                'dependencies' => ['vendor-ui']
            ],
            'button' => [
                'name' => 'Button',
                'css_handle' => 'fleekdash-shared-button',
                'js_handle' => 'fleekdash-shared-ui',
                'dependencies' => ['vendor-ui']
            ],
            'select' => [
                'name' => 'Select',
                'css_handle' => 'fleekdash-shared-select',
                'js_handle' => 'fleekdash-shared-ui',
                'dependencies' => ['vendor-ui']
            ],
            'textarea' => [
                'name' => 'Textarea',
                'css_handle' => 'fleekdash-shared-textarea',
                'js_handle' => 'fleekdash-shared-ui',
                'dependencies' => ['vendor-ui']
            ],
            'badge' => [
                'name' => 'Badge',
                'css_handle' => 'fleekdash-shared-badge',
                'js_handle' => 'fleekdash-shared-ui',
                'dependencies' => ['vendor-ui']
            ],
            'tabs' => [
                'name' => 'Tabs',
                'css_handle' => 'fleekdash-shared-tabs',
                'js_handle' => 'fleekdash-shared-ui',
                'dependencies' => ['vendor-ui']
            ]
        ];
    }

    /**
     * Initialize shared assets for use by MU plugins.
     */
    public function initializeSharedAssets(): void
    {
        // Register shared assets that will be available to MU plugins
        $this->registerSharedAssets();

        // Run head hooks to print the global exposure script
        \add_action('wp_head', [$this, 'exposeComponentsGlobally'], 1);
        \add_action('admin_head', [$this, 'exposeComponentsGlobally'], 1);
    }

    /**
     * Register shared FleekDash build assets.
     */
    private function registerSharedAssets(): void
    {
        $manifest = $this->getManifest();
        if (!$manifest) {
            return;
        }

        // Register main FleekDash bundle chunks to share
        $sharedAssets = [
            'vendor-ui' => 'vendor-ui/vendor-ui.js',
            'vendor-react' => 'vendor-react/vendor-react.js',
            'vendor-utils' => 'vendor-utils/vendor-utils.js'
        ];

        foreach ($sharedAssets as $handle => $file) {
            if (isset($manifest[$file])) {
                \wp_register_script(
                    "fleekdash-shared-{$handle}",
                    $this->getPluginUrl() . "assets/admin/{$manifest[$file]['file']}",
                    [],
                    $this->getAssetVersion($manifest[$file]['file']),
                    true,
                );
            }
        }

        // Register shared CSS
        $sharedCSS = [
            'card' => 'card/card.css',
            'input' => 'input/input.css',
            'button' => 'button/button.css',
            'ui-base' => 'vendor-ui/vendor-ui.css'
        ];

        foreach ($sharedCSS as $handle => $file) {
            if (isset($manifest[$file])) {
                \wp_register_style(
                    "fleekdash-shared-{$handle}",
                    $this->getPluginUrl() . "assets/admin/{$manifest[$file]['file']}",
                    [],
                    $this->getAssetVersion($manifest[$file]['file']),
                );
            }
        }
    }

    /**
     * Expose registered components on window for MU plugin scripts.
     */
    public function exposeComponentsGlobally(): void
    {
        ?>
        <script>
            // Expose FleekDash UI globally for MU plugins
            window.fleekDashSharedComponents = window.fleekDashSharedComponents || {};

            // When FleekDash UI loads, merge exports into the shared namespace
            document.addEventListener( 'DOMContentLoaded', function () {
                if ( window.fleekDashUI ) {
                    Object.assign( window.fleekDashSharedComponents, window.fleekDashUI );
                }
            } );
        </script>
        <?php
    }

    /**
     * Return the list of registerable component keys.
     */
    public function getAvailableComponents(): array
    {
        return $this->registeredComponents;
    }

    /**
     * Build enqueue/config payload for an integration MU plugin.
     */
    public function generateComponentConfig(array $components): array
    {
        $config = [
            'components' => [],
            'assets' => [
                'scripts' => [],
                'styles' => []
            ],
            'globals' => [
                'FleekDashUI' => 'window.fleekDashSharedComponents',
                'React' => 'window.React',
                'ReactDOM' => 'window.ReactDOM'
            ]
        ];

        foreach ($components as $component) {
            if (isset($this->registeredComponents[$component])) {
                $componentData = $this->registeredComponents[$component];

                $config['components'][$component] = [
                    'name' => $componentData['name'],
                    'import' => "window.fleekDashSharedComponents.{$componentData['name']}"
                ];

                // Track asset dependencies for the bundle list
                if (!in_array($componentData['js_handle'], $config['assets']['scripts'])) {
                    $config['assets']['scripts'][] = $componentData['js_handle'];
                }
                if (!in_array($componentData['css_handle'], $config['assets']['styles'])) {
                    $config['assets']['styles'][] = $componentData['css_handle'];
                }
            }
        }

        return $config;
    }

    /**
     * Enqueue shared vendor scripts and styles when required.
     *
     * On FleekDash admin pages the main bundle already loads vendor-react; enqueueing
     * fleekdash-shared-vendor-react again would load react-dom twice and break DevTools/React Scan.
     */
    public function enqueueSharedAssets(): void
    {
        if ($this->assetsEnqueued) {
            return;
        }

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

        $isFleekDashAdminPage = \is_admin()
            && (isset($GLOBALS['pagenow']) && $GLOBALS['pagenow'] === 'admin.php')
            && isset($_GET['page'])
            && strpos((string) $_GET['page'], 'fleekdash') === 0;

        if (!$isFleekDashAdminPage) {
            \wp_enqueue_script('fleekdash-shared-vendor-react');
        }

        \wp_enqueue_script('fleekdash-shared-vendor-ui');
        \wp_enqueue_script('fleekdash-shared-vendor-utils');
        \wp_enqueue_style('fleekdash-shared-ui-base');

        $this->assetsEnqueued = true;
    }

    /**
     * Whether shared vendor bundles should load on this request.
     */
    private function shouldEnqueueSharedAssets(): bool
    {
        // FleekDash integration surfaces or admin routes that need shared chunks
        global $pagenow;

        // FleekDash admin app always needs shared assets
        if (
            \is_admin() && (
                $pagenow === 'admin.php' &&
                isset($_GET['page']) &&
                strpos($_GET['page'], 'fleekdash') === 0
            )
        ) {
            return true;
        }

        // Or any active MU integration that opted into shared components
        $activeIntegrations = $this->getActiveIntegrationsUsingSharedComponents();
        return !empty($activeIntegrations);
    }

    /**
     * List active MU plugins that reference shared components.
     */
    private function getActiveIntegrationsUsingSharedComponents(): array
    {
        // Ensure WordPress plugin API helpers are loaded
        if (!function_exists('get_mu_plugins')) {
            if (defined('ABSPATH') && file_exists(ABSPATH . 'wp-admin/includes/plugin.php')) {
                require_once ABSPATH . 'wp-admin/includes/plugin.php';
            } else {
                return [];
            }
        }

        $muPlugins = get_mu_plugins();
        $usingShared = [];

        foreach ($muPlugins as $plugin => $data) {
            if (strpos($plugin, 'fleekdash-') === 0 && $plugin !== 'fleekdash-integrations-loader.php') {
                // Detect marker string in MU plugin source
                $pluginContent = file_get_contents(WPMU_PLUGIN_DIR . '/' . $plugin);
                if (strpos($pluginContent, 'fleekdash_shared_components') !== false) {
                    $usingShared[] = $plugin;
                }
            }
        }

        return $usingShared;
    }

    /**
     * Resolve FleekDash plugin directory path.
     */
    private function getPluginDir(): string
    {
        // Prefer plugin constant when defined
        if (defined('FLEEKDASH_PLUGIN_DIR')) {
            return FLEEKDASH_PLUGIN_DIR;
        }

        // Fallback: known plugin slug under wp-content/plugins
        return \WP_PLUGIN_DIR . '/fleekdash';
    }

    /**
     * Resolve FleekDash plugin base URL.
     */
    private function getPluginUrl(): string
    {
        // Prefer plugin constant when defined
        if (defined('FLEEKDASH_PLUGIN_URL')) {
            return trailingslashit(FLEEKDASH_PLUGIN_URL);
        }

        // Fallback: plugins_url with known slug
        return trailingslashit(\plugins_url('fleekdash/'));
    }

    /**
     * Load Vite manifest for admin assets.
     */
    private function getManifest(): ?array
    {
        $manifestPath = $this->getPluginDir() . '/assets/admin/manifest.json';

        if (!file_exists($manifestPath)) {
            return null;
        }

        $manifest = json_decode(file_get_contents($manifestPath), true);
        return $manifest ?: null;
    }

    /**
     * Cache-busting version from file mtime.
     */
    private function getAssetVersion(string $file): string
    {
        $filePath = $this->getPluginDir() . "/assets/admin/{$file}";
        return file_exists($filePath) ? filemtime($filePath) : '1.0.0';
    }

    /**
     * Emit PHP snippet for an integration MU plugin to enqueue shared assets.
     */
    public function generateMUPluginComponentsCode(string $integrationId, array $components): string
    {
        $componentsList = implode("', '", $components);
        $safeId = str_replace('-', '_', $integrationId);

        return <<<PHP

// Configure shared components for this integration
add_action('wp_enqueue_scripts', 'fleekdash_{$safeId}_enqueue_shared_components', 8);
add_action('admin_enqueue_scripts', 'fleekdash_{$safeId}_enqueue_shared_components', 8);

function fleekdash_{$safeId}_enqueue_shared_components() {
    // Mark this integration as depending on shared component bundles
    global \$fleekdash_shared_components_needed;
    \$fleekdash_shared_components_needed['{$integrationId}'] = ['{$componentsList}'];

    // Ensure shared assets are enqueued when the integration loads
    if (class_exists('FleekDash\\\\Integrations\\\\Core\\\\SharedComponentsManager')) {
        \$manager = FleekDash\\\\Integrations\\\\Core\\\\SharedComponentsManager::getInstance();
        \$manager->enqueueSharedAssets();
    }
}

PHP;
    }
}
