from __future__ import annotations

import unittest
from http import HTTPStatus

from api_access import ROUTES, required_role
from backend.http import correlation_id, normalize_error_payload
from tools.build_api_registry import build as build_api_registry


class HttpGovernanceTests(unittest.TestCase):
    def test_runtime_registry_resolves_every_declared_route(self) -> None:
        for item in build_api_registry()["routes"]:
            path = (
                item["path"]
                .replace("(\\d{6})", "000001")
                .replace("(\\d+)", "1")
                .replace("(.+)", "sample")
            )
            resolved = ROUTES.resolve(item["method"], path)
            self.assertIsNotNone(resolved, f"{item['method']} {path}")
            self.assertEqual(resolved.feature, item["feature"])
            self.assertEqual(resolved.access, item["access"])

    def test_unknown_route_has_no_runtime_match(self) -> None:
        self.assertIsNone(ROUTES.resolve("GET", "/api/not-registered"))

    def test_compatibility_access_function_uses_runtime_registry(self) -> None:
        self.assertEqual(required_role("GET", "/api/screener/setup"), "member")
        self.assertEqual(required_role("POST", "/api/admin/settings"), "admin")
        self.assertEqual(required_role("GET", "/api/dashboard"), "authenticated")

    def test_errors_keep_legacy_field_and_add_stable_contract(self) -> None:
        result = normalize_error_payload(
            {"error": "invalid input"}, HTTPStatus.BAD_REQUEST, "request-123"
        )
        self.assertEqual(result["error"], "invalid input")
        self.assertEqual(result["message"], "invalid input")
        self.assertEqual(result["code"], "bad_request")
        self.assertEqual(result["request_id"], "request-123")

    def test_correlation_id_rejects_header_injection(self) -> None:
        self.assertEqual(correlation_id("client-request-123"), "client-request-123")
        self.assertRegex(correlation_id("bad\r\nheader"), r"^[0-9a-f]{32}$")


if __name__ == "__main__":
    unittest.main()
