<?php

namespace Core\System;

use Core\App\Services\FooterBuilder;

class App
{
    public function boot()
    {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

        Env::bootstrap(ROOT_PATH);
        $this->loadConfig();
        $this->loadHelpers();
        $this->licenseKernel();
        $this->applyTimezone();

        Language::load();

        if (class_exists(SecurityHeadersMiddleware::class)) {
            (new SecurityHeadersMiddleware())->handle();
        }

        // X-Robots-Tag: noindex for sensitive/functional paths
        $this->applyXRobotsTag();

        if (class_exists(SecurityMiddleware::class)) {
            (new SecurityMiddleware())->handle();
        }

        $this->autoloadModels();
        $this->autoloadControllers();

        PluginManager::loadPlugins();
        ThemeManager::loadActiveTheme();
        ThemeManager::share('footer', FooterBuilder::build());

        if (class_exists(AdminSecurityMiddleware::class)) {
            (new AdminSecurityMiddleware())->handle();
        }

        if (class_exists(Csrf::class)) {
            Csrf::check();
        }

        if (
            class_exists(ContentSeoManager::class)
            && !$this->isAdminUri((string)($_SERVER['REQUEST_URI'] ?? '/'))
        ) {
            ContentSeoManager::start();
        }

        $this->runFrontendPageviewTracker();
        Router::dispatch();
    }

    protected function licenseKernel(): void
    {
        $uri = (string)($_SERVER['REQUEST_URI'] ?? '');

        if (strpos($uri, '/install') !== false || strpos($uri, '/license/recover') !== false || $this->isAssetRequest($uri)) {
            return;
        }

        if (!function_exists('db')) {
            $this->redirectToInstall();
        }

        $base = ROOT_PATH . '/core/system/License/';
        $required = [
            $base . 'LicenseMiddleware.php',
            $base . 'LicenseStorage.php',
            $base . 'LicenseClient.php',
            $base . 'Fingerprint.php',
            $base . 'LicenseException.php',
        ];

        foreach ($required as $file) {
            if (!file_exists($file)) {
                $this->redirectToInstall();
            }
        }

        require_once $base . 'LicenseStorage.php';

        $cache = null;
        try {
            $cls = '\\Core\\System\\License\\LicenseStorage';
            if (class_exists($cls) && method_exists($cls, 'getCache')) {
                $cache = $cls::getCache();
            } elseif (class_exists($cls) && method_exists($cls, 'get')) {
                $cache = $cls::get();
            }
        } catch (\Throwable $e) {
            $cache = null;
        }

        if (!is_array($cache)) {
            $this->redirectToRecovery('missing_license_cache');
        }

        $status = trim((string)($cache['status'] ?? ''));
        if ($status !== 'active') {
            $this->redirectToRecovery('cache_status_not_active');
        }

        $licenseKey = $this->getLicenseKeyDb();
        if ($licenseKey === '') {
            $licenseKey = trim((string)($cache['license_key'] ?? ''));
        }
        if ($licenseKey === '') {
            $this->redirectToRecovery('missing_license_key');
        }

        require_once $base . 'LicenseMiddleware.php';
        $mw = '\\Core\\System\\License\\LicenseMiddleware';

        if (!class_exists($mw) || !method_exists($mw, 'handle')) {
            $this->redirectToRecovery('license_middleware_missing');
        }

        try {
            $mw::handle();
        } catch (\Throwable $e) {
            $this->redirectToRecovery('license_middleware_failed');
        }
    }

    protected function isAssetRequest(string $uri): bool
    {
        $u = strtolower($uri);
        if (strpos($u, '/public/') !== false || strpos($u, '/uploads/') !== false || strpos($u, '/assets/') !== false) {
            return true;
        }

        $qpos = strpos($u, '?');
        if ($qpos !== false) {
            $u = substr($u, 0, $qpos);
        }

        $ext = strtolower((string)pathinfo($u, PATHINFO_EXTENSION));
        if ($ext !== '') {
            $skipExt = [
                'jpg','jpeg','png','gif','webp','svg','ico',
                'css','js','map','woff','woff2','ttf','eot','otf',
                'mp4','webm','mp3','wav','ogg','pdf','zip','rar'
            ];
            if (in_array($ext, $skipExt, true)) {
                return true;
            }
        }

        return false;
    }

    protected function getLicenseKeyDb(): string
    {
        try {
            $pdo = db();
            $stmt = $pdo->prepare("SELECT setting_value FROM settings WHERE setting_key = ? LIMIT 1");
            $stmt->execute(['license_key']);
            $val = $stmt->fetchColumn();
            return trim((string)$val);
        } catch (\Throwable $e) {
            return '';
        }
    }

    protected function basePath(): string
    {
        $script = (string)($_SERVER['SCRIPT_NAME'] ?? '');
        $dir = str_replace('\\', '/', dirname($script));
        if ($dir === '/' || $dir === '.' || $dir === '') {
            return '';
        }
        return rtrim($dir, '/');
    }


    protected function redirectToRecovery(string $reason = 'license_recovery_required'): void
    {
        if (!class_exists(InstallerGuard::class) || !InstallerGuard::isInstalled()) {
            $this->redirectToInstall();
        }

        $base = $this->basePath();
        $query = '?reason=' . rawurlencode($reason);
        header('Location: ' . $base . '/license/recover' . $query, true, 302);
        exit;
    }

    /**
     * Send X-Robots-Tag: noindex for sensitive/functional pages
     */
    protected function applyXRobotsTag(): void
    {
        $uri = parse_url((string)($_SERVER['REQUEST_URI'] ?? '/'), PHP_URL_PATH) ?: '/';

        $noindexPrefixes = [
            '/order/success',
            '/lp-order-form/',
            '/cron/',
            '/license/',
            '/admin',
            '/install',
        ];

        foreach ($noindexPrefixes as $prefix) {
            if ($uri === $prefix || str_starts_with($uri, $prefix)) {
                header('X-Robots-Tag: noindex, nofollow', true);
                return;
            }
        }
    }

    protected function redirectToInstall(): void
    {
        $base = $this->basePath();

        if (class_exists(InstallerGuard::class) && !InstallerGuard::canRunInstaller()) {
            $this->hardBlock('Installer is disabled.');
        }

        header('Location: ' . $base . '/install', true, 302);
        exit;
    }

    protected function hardBlock(string $reason): void
    {
        http_response_code(403);
        echo '<h1>Setup Locked</h1><p>' . htmlspecialchars($reason, ENT_QUOTES, 'UTF-8') . '</p>';
        exit;
    }

    protected function applyTimezone(): void
    {
        try {
            $db = db();

            // Keep PHP and MySQL session on UTC as the stable base timezone.
            // The application already applies the saved GMT offset explicitly in
            // dashboard/statistics queries and UI formatting. Using a named PHP
            // timezone here caused DST-related double shifts.
            date_default_timezone_set('UTC');

            try {
                $db->exec("SET time_zone = '+00:00'");
            } catch (\Throwable $e) {
                // Ignore if the database user cannot change session time zone.
            }
        } catch (\Throwable $e) {
            date_default_timezone_set('UTC');
        }
    }

    protected function isAdminUri(string $uri): bool
    {
        $path = parse_url($uri, PHP_URL_PATH) ?: '/';
        return $path === '/admin' || str_starts_with($path, '/admin/');
    }

    protected function loadConfig(): void
    {
        $configPath = ROOT_PATH . '/core/config/config.php';
        if (is_file($configPath)) {
            require_once $configPath;
        }
    }

    protected function loadHelpers(): void
    {
        foreach (glob(ROOT_PATH . '/core/app/Helpers/*.php') ?: [] as $helper) {
            require_once $helper;
        }
    }

    protected function autoloadModels(): void
    {
        foreach (glob(ROOT_PATH . '/core/app/Models/*.php') ?: [] as $file) {
            require_once $file;
        }
    }

    protected function autoloadControllers(): void
    {
        foreach (glob(ROOT_PATH . '/core/app/Controllers/*.php') ?: [] as $file) {
            require_once $file;
        }
        foreach (glob(ROOT_PATH . '/core/app/Controllers/Admin/*.php') ?: [] as $file) {
            require_once $file;
        }
    }

    protected function runFrontendPageviewTracker(): void
    {
        if ($this->isAdminUri((string)($_SERVER['REQUEST_URI'] ?? '/'))) {
            return;
        }

        $tracker = ROOT_PATH . '/core/app/Controllers/PageViewController.php';
        if (is_file($tracker)) {
            require_once $tracker;
            $class = '\\Core\\App\\Controllers\\PageViewController';
            if (class_exists($class) && method_exists($class, 'track')) {
                try {
                    $class::track();
                } catch (\Throwable $e) {
                    // Never break rendering because of analytics.
                }
            }
        }
    }
}
