<?php

namespace FleekDash\Core;

defined('ABSPATH') || exit;

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

/**
 * Integration Manager V3.0
 *
 * 🔥 Single Source of Truth for all integrations
 * ⚡ Super fast with optimized cache
 * 🎯 Plug & Play: Just create folder + config.json
 * 🚀 Supports both internal integrations and MU plugins
 */
class IntegrationManager // NOSONAR php:S1448 - Legacy manager kept for backward compatibility; split planned in dedicated refactor.
{
    private const REST_NAMESPACE = 'fleekdash/v1';

    private static ?IntegrationManager $instance = null;
    private array $cache = [];
    private array $active = [];
    private bool $initialized = false;

    /**
     * Per-request glob results keyed by md5(path or glob pattern).
     *
     * @var array<string, array<int, string>>
     */
    private array $runtimeDirsCache = [];

    /**
     * Per-request config.json decode keyed by absolute file path.
     *
     * @var array<string, mixed>
     */
    private array $runtimeCfgCache = [];

    private function __construct()
    {
        // Intentionally empty: singleton construction does not require setup.
    }

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

    /**
     * Initialize the system
     */
    public function init(): void
    {
        if ($this->initialized) {
            return;
        }

        // Load active integrations from database
        $this->active = \get_option('fleekdash_v3_active', []) ?? [];

        // Register hooks
        // MIGRATED TO V2.2: Routes now in Api.php (integrations endpoint)
        // \add_action('rest_api_init', [$this, 'registerRestRoutes']);
        \add_action('wp_loaded', [$this, 'loadActiveIntegrations']);

        $this->initialized = true;
    }

    /**
     * Discover all available integrations
     * 🔍 Scans both internal and MU plugin integrations
     */
    public function discover(): array
    {
        if (!empty($this->cache)) {
            return $this->cache;
        }

        $integrations = [];

        // 1. Discover internal integrations
        $internalPath = FLEEKDASH_PLUGIN_DIR . 'integrations';
        $integrations = array_merge($integrations, $this->scanDirectory($internalPath, 'internal'));

        // 2. Discover MU plugin integrations
        $muPath = WP_CONTENT_DIR . '/mu-plugins';
        $integrations = array_merge($integrations, $this->scanMUPlugins($muPath));

        // In-memory only: DB transients here caused concurrent wp_options deadlocks on discovery.
        $this->cache = $integrations;

        return $integrations;
    }

    /**
     * Scan directory for integrations
     */
    private function scanDirectory(string $path, string $mode = 'internal'): array
    {
        $integrations = [];

        if (!is_dir($path)) {
            return $integrations;
        }

        $dirs = $this->getCachedGlobDirectoryListing($path . '/*');

        foreach ($dirs as $dir) {
            $name = basename($dir);

            if ($this->shouldSkipDirectory($mode, $name)) {
                continue;
            }

            $config = $this->resolveIntegrationConfigFromJsonFile($dir . '/config.json', true);
            if ($config === null) {
                continue;
            }

            $integrations[$config['id']] = $this->buildInternalIntegrationEntry($dir, $mode, $config);
        }

        return $integrations;
    }

    /**
     * @return array<int, string>
     */
    private function getCachedGlobDirectoryListing(string $globPattern): array
    {
        $dirKey = md5($globPattern);
        if (!array_key_exists($dirKey, $this->runtimeDirsCache)) {
            $found = glob($globPattern, GLOB_ONLYDIR);
            $this->runtimeDirsCache[$dirKey] = is_array($found) ? $found : [];
        }

        return $this->runtimeDirsCache[$dirKey];
    }

    /**
     * @return array<string, mixed>|null
     */
    private function resolveIntegrationConfigFromJsonFile(string $configFile, bool $requireIntegrationId): ?array
    {
        $config = null;
        if (file_exists($configFile)) {
            if (!array_key_exists($configFile, $this->runtimeCfgCache)) {
                $this->runtimeCfgCache[$configFile] = json_decode(file_get_contents($configFile), true);
            }
            $decoded = $this->runtimeCfgCache[$configFile];
            $idOk = !$requireIntegrationId || (is_array($decoded) && !empty($decoded['id']));
            if ($decoded && $idOk) {
                $config = $decoded;
            }
        }

        return $config;
    }

    /**
     * @param array<string, mixed> $config
     * @return array<string, mixed>
     */
    private function buildInternalIntegrationEntry(string $dir, string $mode, array $config): array
    {
        $hasExternalDeps = isset($config['requires']['plugins']) || isset($config['requires']['themes']);
        $isInstalled = $hasExternalDeps ? $this->checkExternalDependencies($config['requires'] ?? []) : true;

        return [
            'id' => $config['id'],
            'name' => $config['name'] ?? $config['id'],
            'description' => $config['description'] ?? '',
            'version' => $config['version'] ?? '1.0.0',
            'category' => $config['category'] ?? 'plugin',
            'mode' => $mode,
            'path' => $dir,
            'is_active' => in_array($config['id'], $this->active),
            'is_installed' => $isInstalled,
            'is_available' => $this->checkRequirements($config['requires'] ?? []),
            'config' => $config,
        ];
    }

    /**
     * @param array<string, mixed> $config
     * @return array<string, mixed>
     */
    private function buildMuIntegrationEntry(string $dir, string $integrationId, array $config): array
    {
        $hasExternalDeps = isset($config['requires']['plugins']) || isset($config['requires']['themes']);
        $isInstalled = $hasExternalDeps ? $this->checkExternalDependencies($config['requires'] ?? []) : true;

        return [
            'id' => $integrationId,
            'name' => $config['name'] ?? $integrationId,
            'description' => $config['description'] ?? '',
            'version' => $config['version'] ?? '1.0.0',
            'category' => $config['category'] ?? 'plugin',
            'mode' => 'mu',
            'path' => $dir,
            'is_active' => in_array($integrationId, $this->active),
            'is_installed' => $isInstalled,
            'is_available' => $this->checkRequirements($config['requires'] ?? []),
            'config' => $config,
        ];
    }

    private function shouldSkipDirectory(string $mode, string $name): bool
    {
        return $mode === 'internal' && $name === 'Core';
    }

    /**
     * Scan MU plugins for FleekDash integrations
     */
    private function scanMUPlugins(string $path): array
    {
        $integrations = [];

        if (!is_dir($path)) {
            return $integrations;
        }

        $pattern = $path . '/fleekdash-integration-*';
        $dirs = $this->getCachedGlobDirectoryListing($pattern);

        foreach ($dirs as $dir) {
            $integrationId = str_replace('fleekdash-integration-', '', basename($dir));
            $config = $this->resolveIntegrationConfigFromJsonFile($dir . '/config.json', false);
            if ($config === null) {
                continue;
            }

            $integrations[$integrationId] = $this->buildMuIntegrationEntry($dir, $integrationId, $config);
        }

        return $integrations;
    }

    /**
     * Check if external dependencies (plugins/themes) are installed
     */
    private function checkExternalDependencies(array $requires): bool
    {
        // Check plugins are installed (not necessarily active)
        if (isset($requires['plugins'])) {
            foreach ($requires['plugins'] as $plugin) {
                $pluginFile = WP_PLUGIN_DIR . '/' . $plugin;
                if (!file_exists($pluginFile)) {
                    return false;
                }
            }
        }

        // Check themes are installed
        if (isset($requires['themes'])) {
            foreach ($requires['themes'] as $theme) {
                $themeDir = get_theme_root() . '/' . $theme;
                if (!is_dir($themeDir)) {
                    return false;
                }
            }
        }

        return true;
    }

    /**
     * Check if integration requirements are met (for is_available)
     */
    private function checkRequirements(array $requires): bool
    {
        $phpOk = !isset($requires['php']) || version_compare(PHP_VERSION, $requires['php'], '>=');
        $wordpressOk = !isset($requires['wordpress'])
            || version_compare(\get_bloginfo('version'), $requires['wordpress'], '>=');
        $pluginsOk = !isset($requires['plugins']) || $this->areRequiredPluginsActive($requires['plugins']);
        $themesOk = !isset($requires['themes']) || $this->isAnyRequiredThemeActive($requires['themes']);

        return $phpOk && $wordpressOk && $pluginsOk && $themesOk;
    }

    /**
     * @param array<int, string> $plugins
     */
    private function areRequiredPluginsActive(array $plugins): bool
    {
        $allActive = true;
        foreach ($plugins as $plugin) {
            if (!\is_plugin_active($plugin)) {
                $allActive = false;
                break;
            }
        }
        return $allActive;
    }

    /**
     * @param array<int, string> $themes
     */
    private function isAnyRequiredThemeActive(array $themes): bool
    {
        $currentTemplate = \get_template();
        $currentStylesheet = \get_stylesheet();
        $hasActiveTheme = false;

        foreach ($themes as $theme) {
            if ($currentTemplate === $theme || $currentStylesheet === $theme) {
                $hasActiveTheme = true;
                break;
            }
        }

        return $hasActiveTheme;
    }

    /**
     * Get all integrations organized by category
     */
    public function getAll(): array
    {
        $integrations = $this->discover();

        $organized = [
            'plugin' => [],
            'theme' => [],
            'api' => [],
            'app' => []
        ];

        foreach ($integrations as $integration) {
            $category = $integration['category'];

            // Map ecommerce to plugin for UI compatibility
            if ($category === 'ecommerce') {
                $category = 'plugin';
            }

            if (!isset($organized[$category])) {
                $organized[$category] = [];
            }

            $organized[$category][] = $integration;
        }

        return $organized;
    }

    /**
     * Get only active integrations
     */
    public function getActive(): array
    {
        $all = $this->discover();

        return array_filter($all, function ($integration) {
            return $integration['is_active'];
        });
    }

    /**
     * Check if specific integration is active
     */
    public function isActive(string $id): bool
    {
        return in_array($id, $this->active);
    }

    /**
     * Activate integration
     */
    public function activate(string $id): bool
    {
        $integrations = $this->discover();

        if (!isset($integrations[$id])) {
            return false;
        }

        if (!$integrations[$id]['is_available']) {
            return false;
        }

        if (!in_array($id, $this->active)) {
            $this->active[] = $id;
            \update_option('fleekdash_v3_active', $this->active);

            // 🔧 BACKWARD COMPATIBILITY: Also save to standard format
            // Get current active integrations in categorized format
            $active_categorized = \get_option('fleekdash_active_integrations', []);
            if (!is_array($active_categorized)) {
                $active_categorized = [];
            }

            // Determine category from integration data
            $category = $integrations[$id]['category'] ?? 'api';

            // Initialize category if not exists
            if (!isset($active_categorized[$category])) {
                $active_categorized[$category] = [];
            }

            // Add to category if not already there
            if (!in_array($id, $active_categorized[$category], true)) {
                $active_categorized[$category][] = $id;
                \update_option('fleekdash_active_integrations', $active_categorized);
            }
        }

        $this->clearDiscoveryRuntimeCaches();
        $this->cache = [];
        \delete_transient('fleekdash_integrations_cache_v3');

        // 🚀 NEW: Trigger JavaScript event for real-time sync
        $this->triggerJavaScriptEvent('activated', $id);

        // Fire activation hooks
        \do_action('fleekdash_v3_integration_activated', $id);

        return true;
    }

    /**
     * Deactivate integration
     */
    public function deactivate(string $id): bool
    {
        $this->active = array_values(array_diff($this->active, [$id]));
        \update_option('fleekdash_v3_active', $this->active);

        // 🔧 BACKWARD COMPATIBILITY: Also remove from standard format
        $active_categorized = \get_option('fleekdash_active_integrations', []);

        fleekdash_log_info("IntegrationManager V3: Deactivating {$id}");
        fleekdash_log_info("IntegrationManager V3: Before deactivation: " . json_encode($active_categorized));

        if (is_array($active_categorized)) {
            // Remove from all categories and clean up
            foreach ($active_categorized as $category => $integrations) {
                if (is_array($integrations)) {
                    $active_categorized[$category] = array_values(array_diff($integrations, [$id]));
                    // Remove empty categories
                    if (empty($active_categorized[$category])) {
                        unset($active_categorized[$category]);
                    }
                } elseif ($category === '' || $category === null) {
                    // Remove invalid keys
                    unset($active_categorized[$category]);
                }
            }

            fleekdash_log_info("IntegrationManager V3: After deactivation: " . json_encode($active_categorized));
            \update_option('fleekdash_active_integrations', $active_categorized);
        }

        $this->clearDiscoveryRuntimeCaches();
        $this->cache = [];
        \delete_transient('fleekdash_integrations_cache_v3');

        // 🚀 NEW: Trigger JavaScript event for real-time sync
        $this->triggerJavaScriptEvent('deactivated', $id);

        // Fire deactivation hooks
        \do_action('fleekdash_v3_integration_deactivated', $id);

        return true;
    }

    /**
     * Trigger JavaScript event for real-time updates
     */
    private function triggerJavaScriptEvent(string $action, string $integrationId): void
    {
        // Only trigger if we're in a web context (not CLI)
        if (php_sapi_name() === 'cli') {
            return;
        }

        // Add script to trigger JavaScript event on next page load
        \add_action('wp_footer', function () use ($action, $integrationId) {
            ?>
            <script>
                ( function () {
                    // Trigger custom event for real-time sync
                    const event = new CustomEvent( 'fleekdashIntegrationStatusChanged', {
                        detail: {
                            id: '<?php echo \esc_js($integrationId); ?>',
                            action: '<?php echo \esc_js($action); ?>',
                            isActive: <?php echo ($action === 'activated') ? 'true' : 'false'; ?>,
                            timestamp: Date.now()
                        }
                    } );

                    // Dispatch immediately
                    window.dispatchEvent( event );

                    // Also dispatch after a small delay to ensure all systems are ready
                    setTimeout( () => {
                        window.dispatchEvent( event );
                    }, 100 );

                    console.log( '[IntegrationManager] JavaScript event triggered:', event.detail );
                } )();
            </script>
            <?php
        });

        // Also trigger for admin pages
        \add_action('admin_footer', function () use ($action, $integrationId) {
            ?>
            <script>
                ( function () {
                    const event = new CustomEvent( 'fleekdashIntegrationStatusChanged', {
                        detail: {
                            id: '<?php echo \esc_js($integrationId); ?>',
                            action: '<?php echo \esc_js($action); ?>',
                            isActive: <?php echo ($action === 'activated') ? 'true' : 'false'; ?>,
                            timestamp: Date.now()
                        }
                    } );

                    window.dispatchEvent( event );
                    setTimeout( () => window.dispatchEvent( event ), 100 );

                    console.log( '[IntegrationManager] Admin JavaScript event triggered:', event.detail );
                } )();
            </script>
            <?php
        });
    }

    /**
     * Load active integrations
     */
    public function loadActiveIntegrations(): void
    {
        $active = $this->getActive();

        foreach ($active as $integration) {
            $this->loadIntegration($integration);
        }
    }

    /**
     * Load single integration
     */
    private function loadIntegration(array $integration): bool
    {
        $loaded = false;
        $integrationFile = $integration['path'] . '/Integration.php';

        if (file_exists($integrationFile)) {
            try {
                require_once $integrationFile;

                // Get class name
                $className = $this->getIntegrationClassName($integration['id']);

                if (class_exists($className)) {
                    // Create instance
                    $instance = new $className($integration['path']);

                    // Initialize integration
                    if (method_exists($instance, 'init')) {
                        $instance->init();
                    }

                    if (method_exists($instance, 'registerHooks')) {
                        $instance->registerHooks();
                    }

                    if (method_exists($instance, 'registerRestRoutes')) {
                        \add_action('rest_api_init', [$instance, 'registerRestRoutes']);
                    }

                    $loaded = true;
                }
            } catch (\Exception $e) {
                fleekdash_log_error("Failed to load integration {$integration['id']}: " . $e->getMessage());
            }
        }

        return $loaded;
    }

    /**
     * Get integration class name
     */
    private function getIntegrationClassName(string $id): string
    {
        $className = str_replace(' ', '', ucwords(str_replace('-', ' ', $id)));
        return "FleekDash\\Integrations\\{$className}\\Integration";
    }

    /**
     * Register REST API routes
     */
    public function registerRestRoutes(): void
    {
        // Get all integrations
        \register_rest_route(self::REST_NAMESPACE, '/integrations', [
            'methods' => 'GET',
            'callback' => [$this, 'apiGetIntegrations'],
            'permission_callback' => [$this, 'allowPublicIntegrationsCatalog']
        ]);

        // Activate integration
        \register_rest_route(self::REST_NAMESPACE, '/integrations/(?P<id>[a-zA-Z0-9-_]+)/activate', [
            'methods' => 'POST',
            'callback' => [$this, 'apiActivateIntegration'],
            'permission_callback' => function () {
                return \current_user_can('manage_options');
            }
        ]);

        // Deactivate integration
        \register_rest_route(self::REST_NAMESPACE, '/integrations/(?P<id>[a-zA-Z0-9-_]+)/deactivate', [
            'methods' => 'POST',
            'callback' => [$this, 'apiDeactivateIntegration'],
            'permission_callback' => function () {
                return \current_user_can('manage_options');
            }
        ]);
    }

    /**
     * API: Get all integrations
     */
    public function apiGetIntegrations(): \WP_REST_Response
    {
        return \rest_ensure_response($this->getAll()) ?? new \WP_REST_Response([]);
    }

    public function allowPublicIntegrationsCatalog(): bool
    {
        return true;
    }

    /**
     * API: Activate integration
     */
    public function apiActivateIntegration(\WP_REST_Request $request): \WP_REST_Response|\WP_Error
    {
        $id = $request->get_param('id');

        if ($this->activate($id)) {
            return \rest_ensure_response([
                'success' => true,
                'message' => 'Integration activated successfully'
            ]) ?? new \WP_REST_Response([]);
        }

        return new \WP_Error('activation_failed', 'Failed to activate integration', ['status' => 400]) ?? new \WP_REST_Response([]);
    }

    /**
     * API: Deactivate integration
     */
    public function apiDeactivateIntegration(\WP_REST_Request $request): \WP_REST_Response|\WP_Error
    {
        $id = $request->get_param('id');

        if ($this->deactivate($id)) {
            return \rest_ensure_response([
                'success' => true,
                'message' => 'Integration deactivated successfully'
            ]) ?? new \WP_REST_Response([]);
        }

        return new \WP_Error('deactivation_failed', 'Failed to deactivate integration', ['status' => 400]) ?? new \WP_REST_Response([]);
    }

    /**
     * Clear all cache
     */
    public function clearCache(): void
    {
        $this->clearDiscoveryRuntimeCaches();
        $this->cache = [];
    }

    private function clearDiscoveryRuntimeCaches(): void
    {
        $this->runtimeDirsCache = [];
        $this->runtimeCfgCache = [];
    }
}
