<?php

declare(strict_types=1);

namespace WPD_Platform;

use Dollie\SDK\Controllers\IntegrationsController;

/**
 * Integration Loader
 *
 * Loads integrations using PSR-4 autoloading with conditional loading.
 * Only triggers and actions for installed plugins are instantiated.
 *
 * @since 1.0.0
 */
class IntegrationLoader
{
    /**
     * Singleton instance
     *
     * @var self|null
     */
    private static ?self $instance = null;

    /**
     * Base path to integrations directory
     *
     * @var string
     */
    private string $integrationsPath;

    /**
     * List of loaded integrations
     *
     * @var array
     */
    private array $loadedIntegrations = [];

    /**
     * Integration instances cache
     *
     * @var array<string, object>
     */
    private array $integrationInstances = [];

    /**
     * Get singleton instance
     *
     * @return self
     */
    public static function instance(): self
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    /**
     * Constructor
     */
    private function __construct()
    {
        $this->integrationsPath = __DIR__ . '/Integrations';
    }

    /**
     * Load all integrations
     *
     * Phase 1: Load and register all integration classes (lightweight)
     * Phase 2: Only load triggers/actions for integrations where the plugin is installed
     *
     * @return void
     */
    public function load(): void
    {
        if (!is_dir($this->integrationsPath)) {
            return;
        }

        $integrationDirs = glob($this->integrationsPath . '/*', GLOB_ONLYDIR);

        // Phase 1: Register all integrations (always needed for admin display)
        foreach ($integrationDirs as $integrationDir) {
            $this->loadIntegrationClass($integrationDir);
        }

        // Phase 2: Load triggers and actions only for active integrations
        foreach ($integrationDirs as $integrationDir) {
            $integrationName = basename($integrationDir);

            // Check if the integration's plugin is installed before loading triggers/actions
            if ($this->isIntegrationActive($integrationName)) {
                $this->loadTriggersAndActions($integrationDir);
            }

            $this->loadedIntegrations[] = $integrationName;
        }
    }

    /**
     * Load the main integration class
     *
     * @param string $integrationDir Path to integration directory
     * @return void
     */
    private function loadIntegrationClass(string $integrationDir): void
    {
        $integrationName = basename($integrationDir);

        // Find PHP files in the integration root (main integration class)
        $mainFiles = glob($integrationDir . '/*.php');
        foreach ($mainFiles as $file) {
            if (is_file($file)) {
                // Derive class name from file path using PSR-4 convention
                $className = $this->getClassNameFromFile($file);

                if ($className && class_exists($className)) {
                    // The class autoloads via PSR-4, and the file's bottom
                    // calls IntegrationsController::register() when loaded
                    // We need to include the file to trigger registration
                    require_once $file;
                } else {
                    // Fallback: include the file directly
                    require_once $file;
                }
            }
        }
    }

    /**
     * Load triggers and actions for an integration
     *
     * @param string $integrationDir Path to integration directory
     * @return void
     */
    private function loadTriggersAndActions(string $integrationDir): void
    {
        // Load triggers
        $triggersDir = $integrationDir . '/Triggers';
        if (is_dir($triggersDir)) {
            $triggerFiles = glob($triggersDir . '/*.php');
            foreach ($triggerFiles as $file) {
                if (is_file($file)) {
                    require_once $file;
                }
            }
        }

        // Load actions
        $actionsDir = $integrationDir . '/Actions';
        if (is_dir($actionsDir)) {
            $actionFiles = glob($actionsDir . '/*.php');
            foreach ($actionFiles as $file) {
                if (is_file($file)) {
                    require_once $file;
                }
            }
        }
    }

    /**
     * Check if an integration's target plugin is installed
     *
     * @param string $integrationName Folder name of the integration
     * @return bool
     */
    private function isIntegrationActive(string $integrationName): bool
    {
        // Get all registered integrations from the controller
        $integrations = IntegrationsController::get_integrations();

        // Find the integration by matching folder name (case-insensitive)
        foreach ($integrations as $id => $integration) {
            if (strcasecmp($id, $integrationName) === 0) {
                return $integration->is_plugin_installed();
            }
        }

        // If not found in registry, default to loading (backwards compatibility)
        return true;
    }

    /**
     * Derive PSR-4 class name from file path
     *
     * @param string $filePath
     * @return string|null
     */
    private function getClassNameFromFile(string $filePath): ?string
    {
        // Get relative path from Integrations directory
        $relativePath = str_replace($this->integrationsPath . '/', '', $filePath);

        // Remove .php extension
        $relativePath = preg_replace('/\.php$/', '', $relativePath);

        // Convert path to namespace: Academylms/AcademyLMS -> Academylms\AcademyLMS
        $classPath = str_replace('/', '\\', $relativePath);

        // Prepend base namespace
        return 'WPD_Platform\\Integrations\\' . $classPath;
    }

    /**
     * Get list of loaded integrations
     *
     * @return array
     */
    public function getLoadedIntegrations(): array
    {
        return $this->loadedIntegrations;
    }

    /**
     * Check if integrations have been loaded
     *
     * @return bool
     */
    public function isLoaded(): bool
    {
        return !empty($this->loadedIntegrations);
    }
}
