<?php
declare(strict_types=1);

namespace Infolab;

/**
 * Helpers d'émission de réponse JSON.
 * Toujours `Content-Type: application/json; charset=utf-8`.
 * Les contrôleurs ne devraient jamais `echo` directement — passer par ici.
 */
final class Response
{
    /** Réponse JSON standard (objet ou liste). */
    public static function json(mixed $data, int $status = 200): void
    {
        self::emit($status, $data);
    }

    /** Réponse 204 No Content (ou autre statut sans body). */
    public static function noContent(int $status = 204): void
    {
        http_response_code($status);
    }

    /**
     * Erreur uniforme. Toujours { "error": code, "message"?: ..., ...extra }.
     *
     * @param array<string,mixed> $extra
     */
    public static function error(int $status, string $code, ?string $message = null, array $extra = []): void
    {
        $payload = ['error' => $code];
        if ($message !== null) {
            $payload['message'] = $message;
        }
        $payload += $extra;
        self::emit($status, $payload);
    }

    /** Émet une réponse JSON brute. Utilisé par le handler d'exception global. */
    public static function emit(int $status, mixed $data): void
    {
        http_response_code($status);
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    }

    /** Émet les headers CORS basés sur l'env CORS_ORIGIN (défaut '*'). */
    public static function sendCorsHeaders(): void
    {
        $origin = getenv('CORS_ORIGIN') ?: '*';
        header('Access-Control-Allow-Origin: ' . $origin);
        header('Vary: Origin');
        header('Access-Control-Allow-Methods: GET, POST, PATCH, DELETE, OPTIONS');
        header('Access-Control-Allow-Headers: Authorization, Content-Type, Accept');
        header('Access-Control-Max-Age: 86400');
    }
}
