<?php

namespace MintyPHP\Http;

class ApiResponse
{
    public static function success(array $data = [], int $status = 200): never
    {
        self::send($data, $status);
    }

    public static function created(array $data = []): never
    {
        self::success($data, 201);
    }

    public static function noContent(): never
    {
        self::send(null, 204);
    }

    public static function error(string $error, int $status = 400, array $extra = []): never
    {
        $body = array_merge(['error' => $error], $extra);
        self::send($body, $status, $error);
    }

    public static function unauthorized(): never
    {
        self::error('unauthorized', 401);
    }

    public static function forbidden(string $detail = 'forbidden'): never
    {
        self::error($detail, 403);
    }

    public static function notFound(string $detail = 'not_found'): never
    {
        self::error($detail, 404);
    }

    public static function methodNotAllowed(): never
    {
        self::error('method_not_allowed', 405);
    }

    public static function validationError(array $errors): never
    {
        self::error('validation_error', 422, ['errors' => $errors]);
    }

    public static function tooManyRequests(int $retryAfter = 60): never
    {
        self::send(
            ['error' => 'rate_limit_exceeded'],
            429,
            'rate_limit_exceeded',
            ['Retry-After: ' . $retryAfter]
        );
    }

    /**
     * Transform a service result (['ok' => bool, ...] pattern) into an API response.
     */
    public static function fromServiceResult(array $result, int $successStatus = 200): never
    {
        if ($result['ok'] ?? false) {
            $data = $result;
            unset($data['ok']);
            self::success($data, $successStatus);
        }

        $status = (int) ($result['status'] ?? 0);
        if ($status < 400) {
            $status = 422;
        }
        $error = (string) ($result['error'] ?? 'operation_failed');
        $errors = $result['errors'] ?? [];
        $extra = [];
        if ($errors) {
            $extra['errors'] = $errors;
        }
        self::error($error, $status, $extra);
    }

    /**
     * Read JSON request body into an array.
     */
    public static function readJsonBody(): array
    {
        $raw = file_get_contents('php://input');
        if ($raw === false || $raw === '') {
            return [];
        }
        $data = json_decode($raw, true);
        return is_array($data) ? $data : [];
    }

    /**
     * Require specific HTTP method(s).
     */
    public static function requireMethod(string ...$methods): void
    {
        $method = strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET'));
        if (!in_array($method, $methods, true)) {
            self::methodNotAllowed();
        }
    }

    /**
     * Require API authentication.
     */
    public static function requireAuth(): void
    {
        if (!ApiAuth::isAuthenticated()) {
            self::unauthorized();
        }
    }

    /**
     * Require a specific permission key.
     */
    public static function requirePermission(string $key): void
    {
        self::requireAuth();
        if (!ApiAuth::hasPermission($key)) {
            self::forbidden();
        }
    }

    private static function send(?array $body, int $status, ?string $errorCode = null, array $headers = []): never
    {
        http_response_code($status);
        foreach ($headers as $headerLine) {
            header($headerLine);
        }

        if ($body === null) {
            \auditServicesFactory()->createApiAuditService()->finish($status, $errorCode);
            die();
        }

        $json = json_encode($body, JSON_UNESCAPED_UNICODE);
        if (!is_string($json)) {
            $status = 500;
            http_response_code($status);
            $errorCode = $errorCode ?: 'serialization_error';
            $json = json_encode(['error' => 'serialization_error'], JSON_UNESCAPED_UNICODE) ?: '{"error":"serialization_error"}';
        }

        header('Content-Type: application/json; charset=utf-8');
        \auditServicesFactory()->createApiAuditService()->finish($status, $errorCode);
        die($json);
    }
}
