<?php

/**
 * Компілятор SCSS для адмін-панелі
 * Автоматична компіляція SCSS файлів адмінки з відстеженням змін
 *
 * @package Flowaxy\Infrastructure\Compilers
 * @version 1.0.0 Alpha prerelease
 */

declare(strict_types=1);

namespace Flowaxy\Infrastructure\Compilers;

use Flowaxy\Core\System\PathResolver;
use Flowaxy\Support\Helpers\FileHelper;
use Throwable;

use const DS;

final class AdminScssCompiler
{
    private string $scssDir;
    private string $cssDir;
    private string $mainScssFile;
    private string $outputCssFile;
    private ScssCompiler $compiler;

    /**
     * Конструктор
     */
    public function __construct()
    {
        $adminResourcesPath = PathResolver::contentAdmin() . DS . 'resources';
        $this->scssDir = $adminResourcesPath . DS . 'scss';
        $this->cssDir = $adminResourcesPath . DS . 'styles';
        $this->mainScssFile = $this->scssDir . DS . 'main.scss';
        $this->outputCssFile = $this->cssDir . DS . 'flowaxy.css';

        // Використовуємо існуючий ScssCompiler
        $this->compiler = new ScssCompiler(
            $adminResourcesPath,
            'scss/main.scss',
            'styles/flowaxy.css'
        );
    }

    /**
     * Перевірка наявності SCSS файлів
     *
     * @return bool
     */
    public function hasScssFiles(): bool
    {
        return FileHelper::exists($this->mainScssFile) && FileHelper::isReadable($this->mainScssFile);
    }

    /**
     * Компіляція SCSS в CSS з автоматичним відстеженням змін
     *
     * @param bool $force Примусова перекомпіляція
     * @return bool Успішність компіляції
     */
    public function compile(bool $force = false): bool
    {
        if (!$this->hasScssFiles()) {
            error_log("Admin SCSS Compiler: SCSS файли не знайдено для адмінки: " . $this->mainScssFile);
            return false;
        }

        // Перевіряємо, чи потрібна компіляція
        if (!$force && $this->isUpToDate()) {
            return true;
        }

        // Компілюємо - передаем относительные пути, так как ScssCompiler использует $adminResourcesPath как базовый
        $success = $this->compiler->compile('scss/main.scss', 'styles/flowaxy.css');

        if ($success) {
            // Додаємо коментар з датою компіляції
            $this->addCompilationComment();
        } else {
            // Логуємо помилку компіляції
            error_log("Admin SCSS Compiler: Помилка компіляції SCSS адмінки. Main: " . $this->mainScssFile . ", Output: " . $this->outputCssFile . ", SCSS Dir: " . $this->scssDir . ", CSS Dir: " . $this->cssDir);
        }

        return $success;
    }

    /**
     * Перевірка, чи потрібна компіляція
     *
     * @return bool true якщо файли актуальні
     */
    public function isUpToDate(): bool
    {
        if (!FileHelper::exists($this->outputCssFile)) {
            return false;
        }

        // Якщо у CSS присутній BOM (UTF-8), браузер може не застосувати :root змінні.
        // Вважаємо файл неактуальним, щоб примусово перебудувати та очистити BOM.
        $cssCheck = FileHelper::get($this->outputCssFile);
        if ($cssCheck !== false && str_contains($cssCheck, "\xEF\xBB\xBF")) {
            return false;
        }

        // Перевіряємо головний файл
        $mainFileTime = FileHelper::lastModified($this->mainScssFile);
        $outputFileTime = FileHelper::lastModified($this->outputCssFile);

        if ($mainFileTime === false || $outputFileTime === false) {
            return false;
        }

        if ($mainFileTime > $outputFileTime) {
            return false;
        }

        // Перевіряємо всі SCSS файли
        $scssFiles = $this->getAllScssFiles($this->scssDir);
        foreach ($scssFiles as $file) {
            if (FileHelper::exists($file)) {
                $fileTime = FileHelper::lastModified($file);
                if ($fileTime !== false && $fileTime > $outputFileTime) {
                    return false;
                }
            }
        }

        return true;
    }

    /**
     * Отримання всіх SCSS файлів рекурсивно
     *
     * @param string $dir Директорія
     * @return array<string>
     */
    private function getAllScssFiles(string $dir): array
    {
        $files = [];

        if (!FileHelper::isDirectory($dir)) {
            return $files;
        }

        $iterator = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS),
            \RecursiveIteratorIterator::LEAVES_ONLY
        );

        foreach ($iterator as $file) {
            if ($file->isFile() && $file->getExtension() === 'scss') {
                $files[] = $file->getPathname();
            }
        }

        return $files;
    }

    /**
     * Додавання коментаря з датою компіляції в CSS файл
     *
     * @return void
     */
    private function addCompilationComment(): void
    {
        if (!FileHelper::exists($this->outputCssFile)) {
            return;
        }

        $cssContent = FileHelper::get($this->outputCssFile);
        if ($cssContent === false) {
            return;
        }

        // Видаляємо BOM (UTF-8) — він може "ламати" :root і змінні
        $cssContent = str_replace("\xEF\xBB\xBF", '', $cssContent);

        // Перевіряємо, чи вже є коментар про компіляцію
        if (preg_match('/\/\*\s*Compiled:\s*\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}/', $cssContent)) {
            // Оновлюємо існуючий коментар
            $compiledDate = date('Y-m-d H:i:s');
            $cssContent = preg_replace(
                '/\/\*\s*Compiled:\s*\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}.*?\*\//s',
                "/* Compiled: {$compiledDate} - Auto-generated from SCSS. Do not edit manually. */",
                $cssContent,
                1
            );
        } else {
            // Додаємо новий коментар на початок файлу
            $compiledDate = date('Y-m-d H:i:s');
            $comment = "/* Compiled: {$compiledDate} - Auto-generated from SCSS. Do not edit manually. */\n\n";
            $cssContent = $comment . $cssContent;
        }

        FileHelper::put($this->outputCssFile, $cssContent);
    }

    /**
     * Отримання шляху до скомпільованого CSS файлу
     *
     * @return string
     */
    public function getCssPath(): string
    {
        return $this->outputCssFile;
    }

    /**
     * Отримання URL скомпільованого CSS файлу
     *
     * @return string
     */
    public function getCssUrl(): string
    {
        $url = class_exists('\Flowaxy\Support\Helpers\UrlHelper')
            ? \Flowaxy\Support\Helpers\UrlHelper::adminAsset('styles/flowaxy.css')
            : '/content/admin/resources/styles/flowaxy.css';

        // Cache-busting: гарантуємо підвантаження актуального CSS після перекомпіляції
        // (особливо важливо при агресивному кешуванні браузером/проксі).
        $mtime = FileHelper::exists($this->outputCssFile) ? FileHelper::lastModified($this->outputCssFile) : false;
        if ($mtime !== false) {
            $separator = str_contains($url, '?') ? '&' : '?';
            // Не використовуємо "v", бо UrlHelper::adminAsset вже додає ?v=hash
            $url .= $separator . 't=' . $mtime;
        }

        return $url;
    }
}
