<?php
declare(strict_types=1);

// Front controller unique. Toutes les requêtes (sauf fichiers statiques
// existants côté Apache) tombent ici via la réécriture .htaccess.

require __DIR__ . '/../src/bootstrap.php';

use Infolab\Router;
use Infolab\Request;
use Infolab\Response;
use Infolab\Auth;

use Infolab\Controllers\HealthController;
use Infolab\Controllers\CategoriesController;
use Infolab\Controllers\MembersController;
use Infolab\Controllers\ProjectsController;
use Infolab\Controllers\ProjectMembersController;
use Infolab\Controllers\RoadmapController;
use Infolab\Controllers\DiscussionsController;
use Infolab\Controllers\ResourcesController;
use Infolab\Controllers\ActivityController;
use Infolab\Controllers\StatsController;
use Infolab\Controllers\ImagesController;

// CORS systématique, y compris sur la preflight OPTIONS.
Response::sendCorsHeaders();

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

// On instancie Request DANS le try : le parsing JSON peut lever ApiException 400
// si le body est invalide, et on veut une réponse propre plutôt qu'une fatal error.
$router = new Router();

// ----------------------------------------------------------------------------
// Routes publiques (GET, pas de token).
// ----------------------------------------------------------------------------
$router->get('/api/health',                        [HealthController::class,         'index']);

$router->get('/api/categories',                    [CategoriesController::class,     'index']);
$router->get('/api/categories/:slug',              [CategoriesController::class,     'show']);

$router->get('/api/members',                       [MembersController::class,        'index']);
$router->get('/api/members/:slug',                 [MembersController::class,        'show']);

$router->get('/api/projects',                      [ProjectsController::class,       'index']);
$router->get('/api/projects/:slug',                [ProjectsController::class,       'show']);
$router->get('/api/projects/:slug/roadmap',        [RoadmapController::class,        'index']);
$router->get('/api/projects/:slug/members',        [ProjectMembersController::class, 'index']);
$router->get('/api/projects/:slug/discussions',    [DiscussionsController::class,    'index']);
$router->get('/api/projects/:slug/resources',      [ResourcesController::class,      'index']);
$router->get('/api/projects/:slug/images',         [ImagesController::class,         'index']);

$router->get('/api/activity',                      [ActivityController::class,       'index']);
$router->get('/api/stats',                         [StatsController::class,          'index']);

// ----------------------------------------------------------------------------
// Écritures (POST/PATCH/DELETE) — protégées automatiquement par Bearer token
// (le Router marque ces méthodes comme `auth: true`).
// ----------------------------------------------------------------------------
$router->post  ('/api/categories',                            [CategoriesController::class,     'store']);
$router->patch ('/api/categories/:slug',                      [CategoriesController::class,     'update']);
$router->delete('/api/categories/:slug',                      [CategoriesController::class,     'destroy']);

$router->post  ('/api/members',                               [MembersController::class,        'store']);
$router->patch ('/api/members/:slug',                         [MembersController::class,        'update']);
$router->delete('/api/members/:slug',                         [MembersController::class,        'destroy']);

$router->post  ('/api/projects',                              [ProjectsController::class,       'store']);
$router->patch ('/api/projects/:slug',                        [ProjectsController::class,       'update']);
$router->delete('/api/projects/:slug',                        [ProjectsController::class,       'destroy']);

$router->post  ('/api/projects/:slug/members',                [ProjectMembersController::class, 'store']);
$router->patch ('/api/projects/:slug/members/:member_slug',   [ProjectMembersController::class, 'update']);
$router->delete('/api/projects/:slug/members/:member_slug',   [ProjectMembersController::class, 'destroy']);

$router->post  ('/api/projects/:slug/roadmap',                [RoadmapController::class,        'store']);
$router->patch ('/api/projects/:slug/roadmap/:id',            [RoadmapController::class,        'update']);
$router->delete('/api/projects/:slug/roadmap/:id',            [RoadmapController::class,        'destroy']);

$router->post  ('/api/projects/:slug/discussions',            [DiscussionsController::class,    'store']);
$router->patch ('/api/projects/:slug/discussions/:id',        [DiscussionsController::class,    'update']);
$router->delete('/api/projects/:slug/discussions/:id',        [DiscussionsController::class,    'destroy']);

$router->post  ('/api/projects/:slug/resources',              [ResourcesController::class,      'store']);
$router->patch ('/api/projects/:slug/resources/:id',          [ResourcesController::class,      'update']);
$router->delete('/api/projects/:slug/resources/:id',          [ResourcesController::class,      'destroy']);

$router->post  ('/api/projects/:slug/images',                 [ImagesController::class,         'store']);
$router->patch ('/api/projects/:slug/images/:id',             [ImagesController::class,         'update']);
$router->delete('/api/projects/:slug/images/:id',             [ImagesController::class,         'destroy']);

// ----------------------------------------------------------------------------
// Dispatch + handler global d'exceptions.
// ----------------------------------------------------------------------------
try {
    $request = new Request();
    [$route, $params] = $router->dispatch($request->method(), $request->path());

    if ($route['auth']) {
        Auth::requireAdmin($request);
    }

    [$class, $action] = $route['handler'];
    $controller = new $class();
    $controller->$action($request, $params);
} catch (ApiException $e) {
    Response::emit($e->statusCode, $e->payload);
} catch (\Throwable $e) {
    // Toujours loggé vers stderr (visible dans Dozzle côté serveur).
    error_log(sprintf(
        '[unhandled] %s in %s:%d — %s',
        $e::class,
        $e->getFile(),
        $e->getLine(),
        $e->getMessage()
    ));
    $debug = (getenv('APP_DEBUG') ?: 'false') === 'true';
    if ($debug) {
        Response::emit(500, [
            'error'   => 'internal_server_error',
            'message' => $e->getMessage(),
            'class'   => $e::class,
            'file'    => $e->getFile(),
            'line'    => $e->getLine(),
        ]);
    } else {
        Response::emit(500, ['error' => 'internal_server_error']);
    }
}
