<?php

use ScssPhp\ScssPhp\Compiler;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;

/**
 * ThemeManager - Resolves and renders the active theme
 *
 * Responsibilities:
 * - Resolve the active theme directory from config
 * - Load theme.json (title, default_layout, template mapping, colors)
 * - Build a Twig environment rooted at the theme directory
 * - Compile theme SCSS to CSS (in assets/css_compiled/)
 * - Map a requested layout to a concrete .twig template, falling back
 *   to the theme's default_layout when the layout is unknown
 */
class ThemeManager {
    private $config;
    private $themeDir;
    private $themeConfig;
    private $twig;

    /**
     * @param array $config Full CMS config (must contain 'theme_dir' and 'theme')
     */
    public function __construct(array $config) {
        $this->config = $config;
        $this->themeDir = $config['theme_dir'] ?? (__DIR__ . '/../../../themes/' . ($config['active_theme'] ?? 'default'));
        $this->themeConfig = $config['theme'] ?? [];

        $loader = new FilesystemLoader($this->themeDir);
        $this->twig = new Environment($loader, [
            'cache' => false,
            'autoescape' => false,
        ]);
    }

    /**
     * Get the absolute path of the active theme directory
     */
    public function getThemeDir(): string {
        return $this->themeDir;
    }

    /**
     * Get the raw theme.json config array
     */
    public function getThemeConfig(): array {
        return $this->themeConfig;
    }

    /**
     * Get the theme title (from theme.json 'title' or 'name')
     */
    public function getTitle(): string {
        return $this->themeConfig['title'] ?? $this->themeConfig['name'] ?? basename($this->themeDir);
    }

    /**
     * Get the theme config section (default_template, background settings, etc.)
     */
    public function getConfig(): array {
        return $this->themeConfig['config'] ?? [];
    }

    /**
     * Get the theme template section (layout key => .twig file mapping)
     */
    public function getTemplates(): array {
        return $this->themeConfig['template'] ?? [];
    }

    /**
     * Resolve the .twig template file for a requested layout.
     *
     * Templates are defined in theme.json under the "template" section:
     *   { "template": { "full_content": "full_content.twig", ... } }
     * The default template is defined in the "config" section:
     *   { "config": { "default_template": "full_content", ... } }
     *
     * Priority:
     * 1. If the layout is a known key in the "template" section, use its mapped file.
     * 2. Otherwise fall back to config.default_template.
     * 3. Final safety net: full_content.twig.
     *
     * @param string $layout Requested layout key (e.g. 'left_sidebar')
     * @return string Template name usable by the Twig loader
     */
    public function getTemplateForLayout(string $layout): string {
        $layout = trim($layout);
        $templates = $this->getTemplates();

        if ($layout !== '' && isset($templates[$layout])) {
            $file = $templates[$layout];
            if ($this->templateExists($file)) {
                return $file;
            }
        }

        $config = $this->getConfig();
        $default = $config['default_template'] ?? 'full_content';
        if (isset($templates[$default])) {
            $file = $templates[$default];
            if ($this->templateExists($file)) {
                return $file;
            }
        }

        return 'full_content.twig';
    }

    /**
     * Get the list of available layout keys defined in the "template" section.
     *
     * @return array List of layout keys
     */
    public function getLayouts(): array {
        return array_keys($this->getTemplates());
    }

    /**
     * Check whether a template file exists in the theme directory
     */
    private function templateExists(string $file): bool {
        $path = $this->themeDir . '/' . ltrim($file, '/');
        return is_file($path);
    }

    /**
     * Render a layout template with the given data.
     *
     * @param string $layout Requested layout key
     * @param array $data Template variables
     * @return string Rendered HTML
     */
    public function render(string $layout, array $data): string {
        $template = $this->getTemplateForLayout($layout);
        return $this->twig->render($template, $data);
    }

    /**
     * Compile the theme's SCSS to CSS (cached by source mtime).
     * Compiles from assets/scss/theme.scss to assets/css_compiled/theme.css
     *
     * @param bool $force Force recompilation
     * @return string|null Absolute path to the compiled CSS, or null if none
     */
    public function compileCss(bool $force = false): ?string {
        $scssFile = $this->themeDir . '/assets/scss/theme.scss';
        if (!is_file($scssFile)) {
            return null;
        }

        $outDir = $this->themeDir . '/assets/css_compiled';
        $outFile = $outDir . '/theme.css';
        $cacheFile = $outDir . '/.mtime';

        $mtime = filemtime($scssFile);
        if (!$force && is_file($outFile) && is_file($cacheFile) && (int)file_get_contents($cacheFile) === $mtime) {
            return $outFile;
        }

        if (!is_dir($outDir)) {
            mkdir($outDir, 0755, true);
        }

        try {
            $compiler = new Compiler();
            $compiler->setImportPaths($this->themeDir . '/assets/scss');
            $css = $compiler->compileString(file_get_contents($scssFile))->getCss();

            // Remove read-only before writing (file may be locked from previous compile)
            if (is_file($outFile)) {
                @chmod($outFile, 0644);
            }
            if (is_file($cacheFile)) {
                @chmod($cacheFile, 0644);
            }

            file_put_contents($outFile, $css);
            file_put_contents($cacheFile, (string)$mtime);

            // Set read-only to prevent manual edits
            @chmod($outFile, 0444);
            @chmod($cacheFile, 0444);

            return $outFile;
        } catch (\Throwable $e) {
            error_log('ThemeManager SCSS compile error: ' . $e->getMessage());
            return null;
        }
    }

    /**
     * Get the public URL for the theme CSS.
     * Uses assets/css_compiled/theme.css (compiled from SCSS by scssphp).
     */
    public function getCssUrl(): ?string {
        $compiledCss = $this->themeDir . '/assets/css_compiled/theme.css';

        if (is_file($compiledCss)) {
            return $this->getThemeAssetUrl('css_compiled/theme.css');
        }

        $compiled = $this->compileCss();
        if ($compiled !== null) {
            return $this->getThemeAssetUrl('css_compiled/theme.css');
        }
        
        return null;
    }

    /**
     * Get the public URL for the theme JS, or null if unavailable.
     */
    public function getJsUrl(): ?string {
        $jsFile = $this->themeDir . '/assets/js/theme.js';
        if (!is_file($jsFile)) {
            return null;
        }
        return $this->getThemeAssetUrl('js/theme.js');
    }

    /**
     * Get public URL for a theme asset.
     */
    private function getThemeAssetUrl(string $assetPath): string {
        $themeName = basename($this->themeDir);
        return '/themes/' . $themeName . '/assets/' . $assetPath;
    }

    /**
     * Check if theme has SCSS source file.
     */
    public function hasScss(): bool {
        return is_file($this->themeDir . '/assets/scss/theme.scss');
    }

    /**
     * Check if compiled CSS is newer than SCSS source.
     */
    public function isScssCompiled(): bool {
        $scssFile = $this->themeDir . '/assets/scss/theme.scss';
        $cssFile = $this->themeDir . '/assets/css_compiled/theme.css';
        
        if (!is_file($scssFile) || !is_file($cssFile)) {
            return false;
        }
        
        return filemtime($cssFile) >= filemtime($scssFile);
    }

    /**
     * Check if theme has manual CSS file.
     */
    public function hasManualCss(): bool {
        return is_file($this->themeDir . '/assets/css/theme.css');
    }

    /**
     * Get list of CSS files in theme assets/css/ directory.
     * Excludes css_compiled directory.
     */
    public function getCssFiles(): array {
        $cssDir = $this->themeDir . '/assets/css';
        $files = [];
        
        if (!is_dir($cssDir)) {
            return $files;
        }
        
        foreach (scandir($cssDir) as $file) {
            if ($file[0] === '.') continue;
            if (pathinfo($file, PATHINFO_EXTENSION) === 'css') {
                $files[] = $this->getThemeAssetUrl('css/' . $file);
            }
        }
        
        return $files;
    }

    /**
     * Get list of JS files in theme assets/js/ directory.
     */
    public function getJsFiles(): array {
        $jsDir = $this->themeDir . '/assets/js';
        $files = [];
        
        if (!is_dir($jsDir)) {
            return $files;
        }
        
        foreach (scandir($jsDir) as $file) {
            if ($file[0] === '.') continue;
            if (pathinfo($file, PATHINFO_EXTENSION) === 'js') {
                $files[] = $this->getThemeAssetUrl('js/' . $file);
            }
        }
        
        return $files;
    }

    /**
     * Get URL for favicon if it exists.
     */
    public function getFaviconUrl(): ?string {
        $faviconFile = $this->themeDir . '/assets/img/favicon.svg';
        if (!is_file($faviconFile)) {
            return null;
        }
        return $this->getThemeAssetUrl('img/favicon.svg');
    }
}
