<?php

declare(strict_types=1);

use App\Database;
use App\Controllers\AuthController;
use App\Controllers\ChildController;
use App\Controllers\SchoolYearController;
use App\Controllers\ShiftDefinitionController;
use App\Controllers\StructureController;
use App\Controllers\TeacherContractController;
use App\Controllers\TeacherController;
use Firebase\JWT\JWT; // Importa JWT
use Firebase\JWT\Key;  // Importa Key
use Firebase\JWT\ExpiredException;
use Firebase\JWT\SignatureInvalidException;

// 1. Carica Autoloader Composer
require __DIR__ . '/../vendor/autoload.php';

// 2. Carica Variabili d'Ambiente
try {
    $dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/../');
    $dotenv->load();
} catch (\Throwable $th) {
    error_log("Could not load .env file: " . $th->getMessage());
}

// --- Configurazione JWT ---
$jwtSecret = $_ENV['JWT_SECRET'] ?? 'default-secret-change-me';

// --- Funzione Guardia JWT ---
/**
 * Verifica il token JWT dall'header Authorization.
 * Restituisce i dati utente dal payload se valido, altrimenti termina con errore 401.
 * @return array Dati utente dal payload JWT ('sub', 'data')
 */
function authenticate(): array {
    global $jwtSecret; // Rende visibile la chiave segreta definita sopra

    $authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? null;

    if (!$authHeader) {
        http_response_code(401);
        echo json_encode(['error' => 'Authorization header missing']);
        exit;
    }

    // Estrai il token "Bearer <token>"
    if (!preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) {
        http_response_code(401);
        echo json_encode(['error' => 'Malformed Authorization header']);
        exit;
    }

    $jwt = $matches[1];
    if (!$jwt) {
        http_response_code(401);
        echo json_encode(['error' => 'Access token missing']);
        exit;
    }

    try {
        $decoded = JWT::decode($jwt, new Key($jwtSecret, 'HS256'));
        // Restituisce l'intero payload decodificato come array associativo
        return (array)$decoded;
    } catch (ExpiredException $e) {
        http_response_code(401);
        echo json_encode(['error' => 'Token expired']);
        exit;
    } catch (SignatureInvalidException $e) {
         http_response_code(401);
        echo json_encode(['error' => 'Invalid token signature']);
        exit;
    } catch (\Throwable $e) { // Cattura altri errori JWT
        http_response_code(401);
        error_log("JWT Decode Error: " . $e->getMessage());
        echo json_encode(['error' => 'Invalid token']);
        exit;
    }
}


// 3. Imposta Headers CORS
$allowedOrigin = $_ENV['FRONTEND_URL'] ?? 'http://localhost:4200';
header("Access-Control-Allow-Origin: " . $allowedOrigin);
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With");
header("Access-Control-Allow-Credentials: true");

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

header('Content-Type: application/json');

// 4. Definizione Route
$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {

    // --- Public Routes ---
    $r->addRoute('POST', '/api/login', [AuthController::class, 'login']);
    $r->addRoute('GET', '/api/ping', function () { echo json_encode(['message' => 'pong']); });

    // --- Protected Routes (richiedono autenticazione) ---

    // Aggiungiamo un gruppo per applicare la guardia a più route
    $r->addGroup('/api', function (FastRoute\RouteCollector $r) {
        // La guardia verrà chiamata prima dell'handler per queste route

        // Route /api/me (protetta)
        $r->addRoute('GET', '/me', [AuthController::class, 'me']);

        // Structures
        $r->addRoute('GET', '/structures', [StructureController::class, 'index']);
        $r->addRoute('POST', '/structures', [StructureController::class, 'store']);
        $r->addRoute('GET', '/structures/{id:\d+}', [StructureController::class, 'show']);
        $r->addRoute('PUT', '/structures/{id:\d+}', [StructureController::class, 'update']);
        $r->addRoute('DELETE', '/structures/{id:\d+}', [StructureController::class, 'delete']);

        // Teachers
        $r->addRoute('GET', '/teachers', [TeacherController::class, 'index']);
        $r->addRoute('POST', '/teachers', [TeacherController::class, 'store']);
        $r->addRoute('GET', '/teachers/{id:\d+}', [TeacherController::class, 'show']);
        $r->addRoute('PUT', '/teachers/{id:\d+}', [TeacherController::class, 'update']);
        $r->addRoute('DELETE', '/teachers/{id:\d+}', [TeacherController::class, 'delete']);

        // School Years
        $r->addRoute('GET', '/school-years', [SchoolYearController::class, 'index']);
        $r->addRoute('POST', '/school-years', [SchoolYearController::class, 'store']);
        $r->addRoute('GET', '/school-years/{id:\d+}', [SchoolYearController::class, 'show']);
        $r->addRoute('PUT', '/school-years/{id:\d+}', [SchoolYearController::class, 'update']);
        $r->addRoute('DELETE', '/school-years/{id:\d+}', [SchoolYearController::class, 'delete']);

        // Teacher Contracts
        $r->addRoute('GET', '/teacher-contracts', [TeacherContractController::class, 'index']);
        $r->addRoute('POST', '/teacher-contracts', [TeacherContractController::class, 'store']);
        $r->addRoute('GET', '/teacher-contracts/{id:\d+}', [TeacherContractController::class, 'show']);
        $r->addRoute('PUT', '/teacher-contracts/{id:\d+}', [TeacherContractController::class, 'update']);
        $r->addRoute('DELETE', '/teacher-contracts/{id:\d+}', [TeacherContractController::class, 'delete']);

        // Children
        $r->addRoute('GET', '/children', [ChildController::class, 'index']);
        $r->addRoute('POST', '/children', [ChildController::class, 'store']);
        $r->addRoute('GET', '/children/{id:\d+}', [ChildController::class, 'show']);
        $r->addRoute('PUT', '/children/{id:\d+}', [ChildController::class, 'update']);
        $r->addRoute('DELETE', '/children/{id:\d+}', [ChildController::class, 'delete']);

        // Shift Definitions
        $r->addRoute('GET', '/shift-definitions', [ShiftDefinitionController::class, 'index']);
        $r->addRoute('POST', '/shift-definitions', [ShiftDefinitionController::class, 'store']);
        $r->addRoute('GET', '/shift-definitions/{id:\d+}', [ShiftDefinitionController::class, 'show']);
        $r->addRoute('PUT', '/shift-definitions/{id:\d+}', [ShiftDefinitionController::class, 'update']);
        $r->addRoute('DELETE', '/shift-definitions/{id:\d+}', [ShiftDefinitionController::class, 'delete']);

    }); // Fine gruppo /api

});

// 5. Gestione della Richiesta
$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];

if (false !== $pos = strpos($uri, '?')) {
    $uri = substr($uri, 0, $pos);
}
$uri = rawurldecode($uri);

$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
$userData = null; // Inizializza a null

switch ($routeInfo[0]) {
    case FastRoute\Dispatcher::NOT_FOUND:
        http_response_code(404);
        echo json_encode(['error' => 'API Endpoint Not Found']);
        break;
    case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
        $allowedMethods = $routeInfo[1];
        http_response_code(405);
        echo json_encode(['error' => 'Method Not Allowed', 'allowed_methods' => $allowedMethods]);
        break;
    case FastRoute\Dispatcher::FOUND:
        $handler = $routeInfo[1];
        $vars = $routeInfo[2];

        // --- Applica Guardia JWT se la route è protetta (inizia con /api/ e non è /api/login o /api/ping) ---
        if (strpos($uri, '/api/') === 0 && !in_array($uri, ['/api/login', '/api/ping'])) {
             try {
                 $userData = authenticate(); // Verifica token e ottieni dati utente
                 // Potresti aggiungere qui controllo del ruolo se necessario per specifiche route
                 // if ($userData['data']->role !== 'admin' && $uri === '/api/users') { ... }
             } catch (\Exception $e) {
                 // L'eccezione è già gestita dentro authenticate() con exit
                 // Questo blocco catch è per sicurezza, ma non dovrebbe essere raggiunto
                 http_response_code(500);
                 error_log("Unexpected error during authentication check: " . $e->getMessage());
                 echo json_encode(['error' => 'Authentication check failed']);
                 exit;
             }
        }

        // --- Esecuzione Handler ---
        try {
            if (is_callable($handler)) {
                call_user_func($handler, $vars); // Passa $vars alla closure
            } elseif (is_array($handler) && count($handler) === 2 && is_string($handler[0]) && is_string($handler[1])) {
                [$class, $method] = $handler;
                if (class_exists($class) && method_exists($class, $method)) {
                    $controller = new $class();
                    // Passa $vars e $userData (se presente) al metodo del controller
                    // Modifica i metodi del controller per accettare $userData opzionale se serve
                    if ($method === 'me' && $userData !== null) { // Caso speciale per AuthController::me
                         call_user_func([$controller, $method], $userData['data']); // Passa solo il payload 'data'
                    } else {
                         call_user_func([$controller, $method], $vars); // Chiamata standard per gli altri
                    }

                } else {
                    http_response_code(500); error_log("Handler class/method not found: {$class}::{$method}"); echo json_encode(['error' => 'Internal Server Error']);
                }
            } else {
                http_response_code(500); error_log("Invalid handler type defined."); echo json_encode(['error' => 'Internal Server Error']);
            }
        } catch (\Throwable $e) {
            http_response_code(500); error_log("Unhandled error in route handler: " . $e->getMessage() . "\n" . $e->getTraceAsString()); echo json_encode(['error' => 'Internal Server Error']);
        }
        break;
    default:
        http_response_code(500); echo json_encode(['error' => 'Internal Server Error - Dispatcher Error']); break;
}