<?php

/**
 * Оптимізований завантажувач тем
 *
 * Забезпечує кешування, lazy loading, оптимізацію порядку завантаження
 * та інтеграцію з ThemeContainer для ізоляції.
 *
 * @package Flowaxy\Support\Managers
 * @version 1.0.0 Alpha prerelease
 */

declare(strict_types=1);

namespace Flowaxy\Support\Managers;

use Flowaxy\Support\Containers\ThemeContainer;
use Flowaxy\Support\Containers\ThemeContainerFactory;
use Flowaxy\Support\Base\BaseTheme;
use Flowaxy\Support\Helpers\FileHelper;
use Flowaxy\Support\Facades\Log;
use Exception;
use Throwable;

final class ThemeLoader
{
    /**
     * @var array<string, ThemeContainer> Кеш завантажених контейнерів
     */
    private static array $containers = [];

    /**
     * @var array<string, BaseTheme> Кеш завантажених тем
     */
    private static array $themes = [];

    /**
     * @var array<string, array<string, mixed>> Кеш метаданих тем
     */
    private static array $metadata = [];

    /**
     * @var bool Чи ініціалізовано
     */
    private static bool $initialized = false;

    /**
     * @var string Директорія тем
     */
    private static string $themesDir = '';

    /**
     * Ініціалізація завантажувача
     *
     * @param string $themesDir Директорія тем
     * @return void
     */
    public static function initialize(string $themesDir): void
    {
        if (self::$initialized) {
            return;
        }

        self::$themesDir = rtrim($themesDir, '/\\') . DS;
        self::$initialized = true;
    }

    /**
     * Завантаження теми з кешуванням та ізоляцією
     *
     * @param string $themeSlug Slug теми
     * @param array<string, mixed> $themeData Дані теми
     * @return BaseTheme|null Екземпляр теми
     */
    public static function load(string $themeSlug, array $themeData = []): ?BaseTheme
    {
        // Перевіряємо кеш
        if (isset(self::$themes[$themeSlug])) {
            return self::$themes[$themeSlug];
        }

        // Отримуємо або створюємо контейнер
        $container = self::getOrCreateContainer($themeSlug, $themeData);

        if ($container === null) {
            return null;
        }

        // Завантажуємо тему
        $theme = self::loadThemeInstance($themeSlug, $container);

        if ($theme !== null) {
            self::$themes[$themeSlug] = $theme;
        }

        return $theme;
    }

    /**
     * Отримання або створення контейнера теми
     *
     * @param string $themeSlug Slug теми
     * @param array<string, mixed> $themeData Дані теми
     * @return ThemeContainer|null
     */
    private static function getOrCreateContainer(string $themeSlug, array $themeData): ?ThemeContainer
    {
        // Перевіряємо кеш
        if (isset(self::$containers[$themeSlug])) {
            return self::$containers[$themeSlug];
        }

        try {
            // Завантажуємо конфігурацію теми
            $config = self::loadThemeConfig($themeSlug);

            // Створюємо контейнер
            $container = ThemeContainerFactory::create($themeSlug, self::$themesDir . $themeSlug, $config);

            // Зберігаємо в кеш
            self::$containers[$themeSlug] = $container;

            return $container;
        } catch (Exception $e) {
            try {
                Log::Error("Помилка створення контейнера для теми", ['exception' => $e, 'theme_slug' => $themeSlug]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return null;
        }
    }

    /**
     * Завантаження екземпляра теми
     *
     * @param string $themeSlug Slug теми
     * @param ThemeContainer $container Контейнер теми
     * @return BaseTheme|null
     */
    private static function loadThemeInstance(string $themeSlug, ThemeContainer $container): ?BaseTheme
    {
        $themeDir = $container->getThemeDir();

        // Шукаємо головний файл теми
        $themeFile = self::findThemeFile($themeDir, $themeSlug);

        if ($themeFile === null) {
            return null;
        }

        try {
            // Завантажуємо файл
            require_once $themeFile;

            // Шукаємо клас теми
            $themeClass = self::findThemeClass($themeSlug, $themeFile);

            if ($themeClass === null || !class_exists($themeClass)) {
                return null;
            }

            // Створюємо екземпляр з контейнером
            $reflection = new \ReflectionClass($themeClass);
            if ($reflection->isSubclassOf(BaseTheme::class)) {
                $theme = $reflection->newInstance($container);
                return $theme;
            }
        } catch (\Exception $e) {
            try {
                Log::Error("Помилка завантаження екземпляра теми", ['exception' => $e, 'theme_slug' => $themeSlug]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
        }

        return null;
    }

    /**
     * Пошук головного файлу теми
     *
     * @param string $themeDir Директорія теми
     * @param string $themeSlug Slug теми
     * @return string|null Шлях до файлу
     */
    private static function findThemeFile(string $themeDir, string $themeSlug): ?string
    {
        // Основний файл теми (точка входу) - обов'язково з великої літери
        $themeFile = $themeDir . 'Theme.php';

        if (FileHelper::exists($themeFile)) {
            return $themeFile;
        }

        return null;
    }

    /**
     * Пошук класу теми
     *
     * @param string $themeSlug Slug теми
     * @param string $themeFile Шлях до файлу
     * @return string|null Ім'я класу
     */
    private static function findThemeClass(string $themeSlug, string $themeFile): ?string
    {
        // Читаємо файл для пошуку класу
        $content = FileHelper::get($themeFile);
        if ($content === false) {
            return null;
        }

        // Шукаємо клас, що розширює BaseTheme
        if (preg_match('/class\s+(\w+)\s+extends\s+BaseTheme/', $content, $matches)) {
            return $matches[1];
        }

        // Шукаємо будь-який клас
        if (preg_match('/class\s+(\w+)/', $content, $matches)) {
            return $matches[1];
        }

        // Генеруємо ім'я класу з slug
        $parts = explode('-', $themeSlug);
        $className = '';
        foreach ($parts as $part) {
            $className .= ucfirst($part);
        }
        $className .= 'Theme';

        return class_exists($className) ? $className : null;
    }

    /**
     * Завантаження конфігурації теми
     *
     * @param string $themeSlug Slug теми
     * @return array<string, mixed>
     */
    private static function loadThemeConfig(string $themeSlug): array
    {
        // Перевіряємо кеш
        if (isset(self::$metadata[$themeSlug])) {
            return self::$metadata[$themeSlug];
        }

        // Використовуємо ThemeMetadataHelper для читання метаданих
        if (class_exists(\Flowaxy\Support\Helpers\ThemeMetadataHelper::class)) {
            $config = \Flowaxy\Support\Helpers\ThemeMetadataHelper::readMetadata($themeSlug);
            if (is_array($config) && !empty($config)) {
                self::$metadata[$themeSlug] = $config;
                return $config;
            }
        }

        return [];
    }

    /**
     * Отримання завантаженої теми
     *
     * @param string $themeSlug Slug теми
     * @return BaseTheme|null
     */
    public static function get(string $themeSlug): ?BaseTheme
    {
        return self::$themes[$themeSlug] ?? null;
    }

    /**
     * Очищення кешу
     *
     * @param string|null $themeSlug Slug теми (якщо null - очищаємо весь кеш)
     * @return void
     */
    public static function clearCache(?string $themeSlug = null): void
    {
        if ($themeSlug !== null) {
            unset(self::$themes[$themeSlug]);
            unset(self::$containers[$themeSlug]);
            unset(self::$metadata[$themeSlug]);
        } else {
            self::$themes = [];
            self::$containers = [];
            self::$metadata = [];
        }
    }
}
