<?php

declare(strict_types=1);

namespace App\Core;

use App\Controllers\AuthController;
use App\Controllers\BiController;
use App\Controllers\CompatController;
use App\Controllers\DebugController;
use App\Controllers\FunctionsController;
use App\Controllers\HealthController;
use App\Controllers\MapaController;
use App\Controllers\RpcController;
use App\Controllers\StorageController;
use Throwable;

final class App
{
    private const API = '/api/v1';

    public static function run(): void
    {
        Env::load();
        self::securityHeaders();
        self::cors();

        $request = new Request();
        $router = new Router();

        self::registerRoutes($router);

        try {
            $router->dispatch($request);
        } catch (Throwable $e) {
            self::logError('app-dispatch', $e);
            Response::error('Erro interno da API', 500, Env::bool('APP_DEBUG') ? [
                'message' => $e->getMessage(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
            ] : null);
        }
    }

    public static function registerRoutes(Router $router): void
    {
        $health = new HealthController();
        $auth = new AuthController();
        $compat = new CompatController();
        $functions = new FunctionsController();
        $rpc = new RpcController();
        $mapa = new MapaController();
        $storage = new StorageController();
        $bi = new BiController();
        $debug = new DebugController();

        $api = self::API;

        $router->get('/', [$health, 'index'], 'root.health');
        $router->get($api . '/health', [$health, 'index'], 'health.index');

        // Auth
        $router->post($api . '/auth/login', [$auth, 'login'], 'auth.login');
        $router->post($api . '/auth/logout', [$auth, 'logout'], 'auth.logout');
        $router->get($api . '/auth/me', [$auth, 'me'], 'auth.me');
        $router->get($api . '/auth/session', [$auth, 'session'], 'auth.session');
        $router->get($api . '/auth/my-municipalities', [$auth, 'myMunicipalities'], 'auth.my_municipalities');
        $router->post($api . '/auth/select-municipality', [$auth, 'selectMunicipality'], 'auth.select_municipality');
        $router->post($api . '/auth/signup', [$auth, 'signup'], 'auth.signup');
        $router->post($api . '/auth/reset-password-email', [$auth, 'resetPasswordEmail'], 'auth.reset_password_email');
        $router->post($api . '/auth/update-user', [$auth, 'updateUser'], 'auth.update_user');

        // Supabase compatibility layer
        $router->post($api . '/functions/lookup-municipios', [$functions, 'lookupMunicipios'], 'functions.lookup_municipios.post');
        $router->get($api . '/functions/lookup-municipios', [$functions, 'lookupMunicipios'], 'functions.lookup_municipios.get');
        $router->post($api . '/functions/admin-create-user', [$functions, 'adminCreateUser'], 'functions.admin_create_user');
        $router->post($api . '/functions/admin-update-user', [$functions, 'adminUpdateUser'], 'functions.admin_update_user');
        $router->post($api . '/functions/admin-reset-password', [$functions, 'adminResetPassword'], 'functions.admin_reset_password');
        $router->post($api . '/rpc/count_tentativas_falhas', [$rpc, 'countTentativasFalhas'], 'rpc.count_tentativas_falhas');

        $router->get($api . '/compat/{table}', [$compat, 'select'], 'compat.select');
        $router->post($api . '/compat/{table}', [$compat, 'insert'], 'compat.insert');
        $router->patch($api . '/compat/{table}', [$compat, 'update'], 'compat.update');
        $router->delete($api . '/compat/{table}', [$compat, 'delete'], 'compat.delete');

        // Storage
        $router->get($api . '/storage/public/{*path}', function (Request $request, array $params = []) use ($storage): void { $storage->public($request); }, 'storage.public');
        $router->post($api . '/storage/{bucket}/upload', function (Request $request, array $params = []) use ($storage): void { $storage->upload($request); }, 'storage.upload');

        // BI / Indicadores
        if (method_exists($bi, 'indicadores')) {
            $router->get($api . '/bi/indicadores', [$bi, 'indicadores'], 'bi.indicadores');
        }
        if (method_exists($bi, 'iptuConfigEndpoint')) {
            $router->get($api . '/bi/iptu/config', [$bi, 'iptuConfigEndpoint'], 'bi.iptu.config');
        }
        if (method_exists($bi, 'iptuResumo')) {
            $router->get($api . '/bi/iptu/resumo', [$bi, 'iptuResumo'], 'bi.iptu.resumo');
        }
        if (method_exists($bi, 'iptuStatus')) {
            $router->get($api . '/bi/iptu/status', [$bi, 'iptuStatus'], 'bi.iptu.status');
        }
        if (method_exists($bi, 'iptuMapa')) {
            $router->get($api . '/bi/iptu/mapa', [$bi, 'iptuMapa'], 'bi.iptu.mapa');
        }
        if (method_exists($bi, 'iptuImovel')) {
            $router->get($api . '/bi/iptu/imovel', [$bi, 'iptuImovel'], 'bi.iptu.imovel');
        }
        if (method_exists($bi, 'clearCache')) {
            $router->post($api . '/bi/iptu/cache/clear', [$bi, 'clearCache'], 'bi.iptu.cache.clear');
        }

        // Mapa / WebGIS
        $router->get($api . '/mapa/health', [$mapa, 'health'], 'mapa.health');
        $router->get($api . '/mapa/token-status', [$mapa, 'tokenStatus'], 'mapa.token_status');
        $router->post($api . '/mapa/token-refresh', [$mapa, 'tokenRefresh'], 'mapa.token_refresh');
        $router->get($api . '/mapa/config', [$mapa, 'config'], 'mapa.config');
        $router->get($api . '/mapa/fotos360', [$mapa, 'fotos360'], 'mapa.fotos360');
        $router->post($api . '/mapa/fotos360/upload', [$mapa, 'upload360'], 'mapa.fotos360.upload');
        $router->get($api . '/mapa/consulta-el', [$mapa, 'consultaEl'], 'mapa.consulta_el.get');
        $router->post($api . '/mapa/consulta-el', [$mapa, 'consultaEl'], 'mapa.consulta_el.post');
        $router->post($api . '/mapa/export/shp', [$mapa, 'exportShp'], 'mapa.export.shp');

        // Diagnóstico padronizado
        $router->get($api . '/debug/migration-check', [$debug, 'migrationCheck'], 'debug.migration_check');
        $router->get($api . '/debug/routes', static function (Request $request, array $params = []) use ($router): void {
            Response::json([
                'success' => true,
                'api_prefix' => self::API,
                'routes' => $router->routes(),
            ]);
        }, 'debug.routes');
    }

    private static function securityHeaders(): void
    {
        header('X-Content-Type-Options: nosniff');
        header('X-Frame-Options: SAMEORIGIN');
        header('Referrer-Policy: strict-origin-when-cross-origin');
    }

    private static function cors(): void
    {
        $origin = $_SERVER['HTTP_ORIGIN'] ?? '';
        $allowed = array_filter(array_map('trim', explode(',', Env::get('CORS_ORIGINS', '') ?? '')));

        if (!$allowed) {
            $allowed = ['http://localhost:8080', 'http://127.0.0.1:8080', 'http://localhost:5173', 'http://127.0.0.1:5173'];
        }

        if ($origin !== '' && (in_array('*', $allowed, true) || in_array($origin, $allowed, true))) {
            header('Access-Control-Allow-Origin: ' . (in_array('*', $allowed, true) ? $origin : $origin));
            header('Vary: Origin');
            header('Access-Control-Allow-Credentials: true');
        }

        header('Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS');
        header('Access-Control-Allow-Headers: Authorization, Content-Type, Cache-Control, Pragma, Expires, X-Requested-With, X-Compat-Select, X-Compat-Filters, X-Compat-Order, X-Compat-Limit, X-Compat-Range, X-Compat-Count, X-Compat-Head, X-Refresh-Token, X-Municipality-Id');
        header('Access-Control-Expose-Headers: Content-Range, X-Total-Count, X-Sisprom-Asset-Path');

        if (($_SERVER['REQUEST_METHOD'] ?? '') === 'OPTIONS') {
            http_response_code(204);
            exit;
        }
    }

    private static function logError(string $context, Throwable $e): void
    {
        $root = dirname(__DIR__, 2);
        $dir = $root . DIRECTORY_SEPARATOR . 'storage' . DIRECTORY_SEPARATOR . 'logs';
        if (!is_dir($dir)) @mkdir($dir, 0777, true);
        @file_put_contents($dir . DIRECTORY_SEPARATOR . 'api-error.log', '[' . date(DATE_ATOM) . "] {$context}: " . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine() . PHP_EOL, FILE_APPEND);
    }
}
