<?php

declare(strict_types=1);

class Router {
    // Préfixe fixe de l'API (toujours 'api')
    private const API_PREFIX = 'api';
    private array $routes = [];
    private array $publicEndpoints = [
        'login',
        'register',
        'lostpassword',
        'log',
        'health', // Health check endpoint pour monitoring et déploiement
        'villes', // Ajout de la route villes comme endpoint public pour l'autocomplétion du code postal
        'password/check', // Vérification de la force des mots de passe (public pour l'inscription)
        'password/compromised', // Vérification si un mot de passe est compromis
        'stripe/webhooks', // Webhook Stripe (doit être public pour recevoir les événements)
    ];

    public function __construct() {
        // Pas besoin de récupérer AppConfig puisque nous utilisons une constante pour le préfixe API
        $this->configureRoutes();
    }

    /**
     * Configure toutes les routes de l'application
     */
    private function configureRoutes(): void {
        // Routes publiques
        $this->post('login', ['LoginController', 'login']);
        $this->post('register', ['LoginController', 'register']);
        $this->post('lostpassword', ['LoginController', 'lostPassword']);

        // Route pour les logs
        $this->post('log', ['LogController', 'index']);

        // Route health check (monitoring et déploiement)
        $this->get('health', ['HealthController', 'check']);

        // Routes privées utilisateurs
        // IMPORTANT: Les routes spécifiques doivent être déclarées AVANT les routes avec paramètres
        $this->post('users/check-username', ['UserController', 'checkUsername']);  // Déplacé avant les routes avec :id
        $this->post('users/device-info', ['UserController', 'saveDeviceInfo']);  // Endpoint pour sauvegarder les infos du device
        $this->get('users', ['UserController', 'getUsers']);
        $this->get('users/:id', ['UserController', 'getUserById']);
        $this->post('users', ['UserController', 'createUser']);
        $this->put('users/:id', ['UserController', 'updateUser']);
        $this->delete('users/:id', ['UserController', 'deleteUser']);
        $this->post('users/:id/reset-password', ['UserController', 'resetPassword']);
        $this->post('logout', ['LoginController', 'logout']);
        $this->get('user/session', ['LoginController', 'refreshSession']);

        // Routes entités
        $this->get('entites', ['EntiteController', 'getEntites']);
        $this->get('entites/:id', ['EntiteController', 'getEntiteById']);
        $this->get('entites/postal/:code', ['EntiteController', 'getEntiteByPostalCode']);
        $this->put('entites/:id', ['EntiteController', 'updateEntite']);
        $this->post('entites/:id/logo', ['EntiteController', 'uploadLogo']);
        $this->get('entites/:id/logo', ['EntiteController', 'getLogo']);

        // Routes opérations
        $this->get('operations', ['OperationController', 'getOperations']);
        $this->get('operations/:id', ['OperationController', 'getOperationById']);
        $this->post('operations', ['OperationController', 'createOperation']);
        $this->put('operations/:id', ['OperationController', 'updateOperation']);
        $this->delete('operations/:id', ['OperationController', 'deleteOperation']);

        // Routes d'export d'opérations
        $this->get('operations/:id/export/excel', ['OperationController', 'exportExcel']);
        $this->get('operations/:id/export/json', ['OperationController', 'exportJson']);
        $this->get('operations/:id/export/full', ['OperationController', 'exportFull']);
        $this->get('operations/:id/backups', ['OperationController', 'getBackups']);
        $this->get('operations/:id/backups/:backup_id', ['OperationController', 'downloadBackup']);
        $this->delete('operations/:id/backups/:backup_id', ['OperationController', 'deleteBackup']);

        // Routes passages
        $this->get('passages', ['PassageController', 'getPassages']);
        $this->get('passages/:id', ['PassageController', 'getPassageById']);
        $this->get('passages/:id/receipt', ['PassageController', 'getReceipt']);
        $this->get('passages/operation/:operation_id', ['PassageController', 'getPassagesByOperation']);
        $this->post('passages', ['PassageController', 'createPassage']);
        $this->put('passages/:id', ['PassageController', 'updatePassage']);
        $this->delete('passages/:id', ['PassageController', 'deletePassage']);

        // Routes villes
        $this->get('villes', ['VilleController', 'searchVillesByPostalCode']);

        // Routes fichiers
        $this->get('files/browse', ['FileController', 'browse']);
        $this->get('files/search', ['FileController', 'search']);
        $this->get('files/stats', ['FileController', 'getStats']);
        $this->get('files/metadata', ['FileController', 'getMetadata']);
        $this->get('files/list/:support/:id', ['FileController', 'listBySupport']);
        $this->get('files/info/:id', ['FileController', 'getFileInfo']);
        $this->get('files/download/:id', ['FileController', 'download']);
        $this->delete('files/:id', ['FileController', 'deleteFile']);

        // Routes secteurs
        $this->get('sectors', ['SectorController', 'index']);
        $this->post('sectors', ['SectorController', 'create']);
        $this->put('sectors/:id', ['SectorController', 'update']);
        $this->delete('sectors/:id', ['SectorController', 'delete']);
        
        // Routes mots de passe
        $this->post('password/check', ['PasswordController', 'checkStrength']);
        $this->post('password/compromised', ['PasswordController', 'checkCompromised']);
        $this->get('password/generate', ['PasswordController', 'generate']);
        
        // Routes du module Chat
        $this->get('chat/rooms', ['ChatController', 'getRooms']);
        $this->post('chat/rooms', ['ChatController', 'createRoom']);
        $this->put('chat/rooms/:id', ['ChatController', 'updateRoom']);
        $this->delete('chat/rooms/:id', ['ChatController', 'deleteRoom']);
        $this->get('chat/rooms/:id/messages', ['ChatController', 'getRoomMessages']);
        $this->post('chat/rooms/:id/messages', ['ChatController', 'sendMessage']);
        $this->put('chat/messages/:id', ['ChatController', 'updateMessage']);
        $this->post('chat/rooms/:id/read', ['ChatController', 'markAsRead']);
        $this->get('chat/recipients', ['ChatController', 'getRecipients']);
        
        // Routes du module Sécurité (Admin uniquement)
        $this->get('admin/metrics', ['SecurityController', 'getMetrics']);
        $this->get('admin/alerts', ['SecurityController', 'getAlerts']);
        $this->post('admin/alerts/:id/resolve', ['SecurityController', 'resolveAlert']);
        $this->get('admin/blocked-ips', ['SecurityController', 'getBlockedIPs']);
        $this->post('admin/unblock-ip', ['SecurityController', 'unblockIP']);
        $this->post('admin/block-ip', ['SecurityController', 'blockIP']);
        $this->get('admin/security-report', ['SecurityController', 'getSecurityReport']);
        $this->post('admin/cleanup', ['SecurityController', 'cleanup']);
        $this->post('admin/test-alert', ['SecurityController', 'testAlert']);
        
        // Routes Stripe
        // Configuration et onboarding
        $this->post('stripe/accounts', ['StripeController', 'createAccount']);
        $this->get('stripe/accounts/:entityId/status', ['StripeController', 'getAccountStatus']);
        $this->post('stripe/accounts/:accountId/onboarding-link', ['StripeController', 'createOnboardingLink']);

        // Tap to Pay - Configuration
        $this->post('stripe/locations', ['StripeController', 'createLocation']);
        $this->post('stripe/terminal/connection-token', ['StripeController', 'createConnectionToken']);

        // Paiements
        $this->post('stripe/payments/create-intent', ['StripeController', 'createPaymentIntent']);
        $this->post('stripe/payments/cancel', ['StripeController', 'cancelPayment']);
        $this->post('stripe/payment-links', ['StripeController', 'createPaymentLink']);
        $this->get('stripe/payments/:paymentIntentId', ['StripeController', 'getPaymentStatus']);

        // Statistiques et configuration
        $this->get('stripe/stats', ['StripeController', 'getPaymentStats']);
        $this->get('stripe/config', ['StripeController', 'getPublicConfig']);

        // Webhook (IMPORTANT: pas d'authentification requise pour les webhooks Stripe)
        $this->post('stripe/webhooks', ['StripeWebhookController', 'handleWebhook']);

        // Routes Statistiques Events (Admin uniquement)
        $this->get('events/stats/summary', ['EventStatsController', 'summary']);
        $this->get('events/stats/daily', ['EventStatsController', 'daily']);
        $this->get('events/stats/weekly', ['EventStatsController', 'weekly']);
        $this->get('events/stats/monthly', ['EventStatsController', 'monthly']);
        $this->get('events/stats/details', ['EventStatsController', 'details']);
        $this->get('events/stats/types', ['EventStatsController', 'types']);

        // Routes Migration (Admin uniquement)
        $this->get('migrations/test-connections', ['MigrationController', 'testConnections']);
        $this->get('migrations/entities/available', ['MigrationController', 'getAvailableEntities']);
        $this->get('migrations/entities/:id', ['MigrationController', 'getEntityDetails']);
        $this->post('migrations/entity', ['MigrationController', 'migrateEntity']);
        $this->post('migrations/entity/step', ['MigrationController', 'migrateEntityStep']);
        $this->get('migrations/entity/:id/status', ['MigrationController', 'getMigrationStatus']);
        $this->get('migrations/entity/:id/logs', ['MigrationController', 'getMigrationLogs']);
        $this->get('migrations/entity/:id/report', ['MigrationController', 'getMigrationReport']);
        $this->get('migrations/entity/:id/compare', ['MigrationController', 'compareEntityData']);
        $this->get('migrations/entity/:id/verify', ['MigrationController', 'verifyMigration']);
        $this->delete('migrations/entity/:id', ['MigrationController', 'rollbackEntity']);
        $this->delete('migrations/entity/:id/step/:step', ['MigrationController', 'rollbackStep']);
    }

    public function handle(): void {
        $method = $_SERVER['REQUEST_METHOD'];
        $uri = $this->normalizeUri($_SERVER['REQUEST_URI']);

        // error_log("Initial URI: $uri");

        // Handle CORS preflight
        if ($method === 'OPTIONS') {
            header('HTTP/1.1 200 OK');
            exit();
        }

        // Prendre le préfixe API à partir de la constante
        $apiPrefix = self::API_PREFIX;

        // Vérifier si l'URI commence bien par le préfixe API
        $prefixMatch = strpos($uri, $apiPrefix) === 0;

        if (!$prefixMatch) {
            Response::json([
                'error' => 'Invalid API prefix',
                'path' => $uri,
                'expected_prefix' => $apiPrefix
            ], 404);
            return;
        }

        // Extraire l'endpoint en retirant le préfixe API
        $endpoint = substr($uri, strlen($apiPrefix) + 1); // +1 pour le slash
        $endpoint = trim($endpoint, '/');

        // Check if endpoint is public
        if ($this->isPublicEndpoint($endpoint)) {
            $route = $this->findRoute($method, $endpoint);
            if ($route) {
                $this->executeRoute($route);
                return;
            }
        } else {
            // error_log("Private endpoint: $endpoint");
            // Private route - check auth first
            Session::requireAuth();

            $route = $this->findRoute($method, $endpoint);
            if ($route) {
                $this->executeRoute($route);
                return;
            }
        }

        // No route found
        Response::json([
            'error' => 'Route not found',
            'endpoint' => $endpoint,
            'uri' => $uri
        ], 404);
    }

    private function normalizeUri(string $uri): string {
        return trim(preg_replace('#/+#', '/', parse_url($uri, PHP_URL_PATH)), '/');
    }

    private function isPublicEndpoint(string $endpoint): bool {
        return in_array($endpoint, $this->publicEndpoints);
    }

    private function executeRoute(array $route): void {
        [$controllerName, $method] = $route['handler'];

        // Essayer de trouver le contrôleur en tenant compte des namespaces possibles
        $classNames = [
            $controllerName,                  // Sans namespace
            "\\App\\Controllers\\$controllerName", // Avec namespace complet
            "\\$controllerName"               // Avec namespace racine
        ];

        $controllerClass = null;
        foreach ($classNames as $className) {
            if (class_exists($className)) {
                $controllerClass = $className;
                break;
            }
        }

        if ($controllerClass === null) {
            // Classe non trouvée, gérer l'erreur
            Response::json([
                'error' => 'Controller not found',
                'controller' => $controllerName,
                'status' => 'error',
                'message' => 'Controller not found',
                'tried_namespaces' => implode(', ', $classNames)
            ], 404);
            return;
        }

        $controller = new $controllerClass();

        if (!empty($route['params'])) {
            $controller->$method(...$route['params']);
        } else {
            $controller->$method();
        }
    }

    public function get(string $path, array $handler): void {
        $this->addRoute('GET', $path, $handler);
    }

    public function post(string $path, array $handler): void {
        $this->addRoute('POST', $path, $handler);
    }

    public function put(string $path, array $handler): void {
        $this->addRoute('PUT', $path, $handler);
    }

    public function delete(string $path, array $handler): void {
        $this->addRoute('DELETE', $path, $handler);
    }

    private function addRoute(string $method, string $path, array $handler): void {
        // Normalize the path
        $path = trim($path, '/');
        $this->routes[$method][$path] = $handler;
    }

    private function findRoute(string $method, string $uri): ?array {
        if (!isset($this->routes[$method])) {
            // error_log("Méthode $method non trouvée dans les routes");
            return null;
        }

        $uri = trim($uri, '/');
        // Désactiver les logs de debug en production
        // error_log("Recherche de route pour: méthode=$method, uri=$uri");
        // error_log("Routes disponibles pour $method: " . implode(', ', array_keys($this->routes[$method])));

        foreach ($this->routes[$method] as $route => $handler) {
            // Correction: utiliser :param au lieu de {param}
            $pattern = preg_replace('/:([^\/]+)/', '([^/]+)', $route);
            $pattern = "@^" . $pattern . "$@D";
            // error_log("Test pattern: $pattern contre uri: $uri");

            if (preg_match($pattern, $uri, $matches)) {
                // error_log("Route trouvée! Pattern: $pattern, Handler: {$handler[0]}::{$handler[1]}");
                array_shift($matches);
                return [
                    'handler' => $handler,
                    'params' => $matches
                ];
            }
        }

        // error_log("Aucune route trouvée pour $method $uri");

        return null;
    }
}
