<?php

namespace App\Core;

/**
 * Ponto central da aplicação.
 * Inicializa configurações, autoloader e timezone.
 */
class Application
{
    private array $config;
    private Router $router;

    public function __construct(array $config)
    {
        $this->config = $config;
        $this->router = new Router();

        $this->bootstrap();
    }

    // -------------------------------------------------------------------------
    // Inicialização
    // -------------------------------------------------------------------------

    private function bootstrap(): void
    {
        // Sessão global (período persistente)
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

        // Timezone
        date_default_timezone_set($this->config['timezone'] ?? 'America/Sao_Paulo');

        // Exibição de erros conforme ambiente
        if ($this->config['debug'] ?? false) {
            ini_set('display_errors', '1');
            error_reporting(E_ALL);
        } else {
            ini_set('display_errors', '0');
            error_reporting(0);
        }

        // Configura o diretório de views
        View::setViewPath($this->config['root_path'] . '/app/Views');

        // Auto-limpeza de cache no UPGRADE — detecta mudança da Versao::ATUAL
        // entre execucoes e limpa storage/cache + opcache automaticamente.
        // Roda 1 vez por upgrade (a primeira request); demais saem direto.
        $this->autoLimparCacheNoUpgrade();

        // v1.4.8.2: Housekeeping de cache (1x a cada 10 min) — apaga arquivos
        // EXPIRADOS órfãos (chaves que ninguém mais consulta). Resolve o problema
        // de acumular centenas de JSON velhos de períodos antigos.
        $this->housekeepingCache();
    }

    /** Limpa caches expirados periodicamente (a cada 10 min, marcado por timestamp). */
    private function housekeepingCache(): void
    {
        try {
            $root = $this->config['root_path'] ?? '';
            $marcador = $root . '/storage/.housekeeping';
            $ultimo = is_file($marcador) ? (int) @file_get_contents($marcador) : 0;
            if (time() - $ultimo < 600) return; // 10 min entre execuções
            @file_put_contents($marcador, (string) time());
            \App\Core\Cache::limparExpirados();
        } catch (\Throwable) {
            // Housekeeping nunca deve quebrar o boot
        }
    }

    /**
     * Detecta upgrade comparando Versao::ATUAL com a versao gravada em
     * storage/.versao_executada. Se mudou, limpa cache de arquivo + opcache.
     * Silencioso: qualquer erro é ignorado (não bloqueia o boot).
     */
    private function autoLimparCacheNoUpgrade(): void
    {
        try {
            $root      = $this->config['root_path'] ?? '';
            $marcador  = $root . '/storage/.versao_executada';
            $versaoAt  = Versao::ATUAL;
            $versaoAnt = is_file($marcador) ? trim((string) @file_get_contents($marcador)) : '';

            if ($versaoAnt === $versaoAt) return; // sem upgrade, nada a fazer

            // 1) Apaga JSONs de cache (Cache::lembrar grava 1 .json por chave)
            $cacheDir = $root . '/storage/cache';
            if (is_dir($cacheDir)) {
                $apagados = 0;
                foreach (glob($cacheDir . '/*.json') ?: [] as $f) {
                    if (@unlink($f)) $apagados++;
                }
                $log = sprintf("[%s] upgrade %s -> %s : %d caches apagados\n",
                    date('Y-m-d H:i:s'), $versaoAnt ?: '(nova instalação)', $versaoAt, $apagados);
                @file_put_contents($root . '/storage/logs/upgrade.log', $log, FILE_APPEND);
            }

            // 2) Reset opcache (zera classes PHP cacheadas em memoria)
            if (function_exists('opcache_reset')) @opcache_reset();

            // 3) Grava nova versao (so depois de tudo dar certo) — proximas
            //    requests pulam a checagem ate o proximo upgrade.
            @file_put_contents($marcador, $versaoAt);
        } catch (\Throwable) {
            // Nunca bloqueia o boot por causa de cache.
        }
    }

    // -------------------------------------------------------------------------
    // Acesso ao roteador
    // -------------------------------------------------------------------------

    public function getRouter(): Router
    {
        return $this->router;
    }

    // -------------------------------------------------------------------------
    // Execução
    // -------------------------------------------------------------------------

    public function run(): void
    {
        $this->router->resolve();
    }
}
