"""Transport-level bearer protection for the ARR MCP ASGI application."""

from __future__ import annotations

import hashlib
import hmac
import os
from dataclasses import dataclass, field
from typing import Any, Awaitable, Callable, Dict, List, Tuple


MCP_BEARER_ENV = "ARR_MCP_BEARER_TOKEN"
ASGIApp = Callable[
    [Dict[str, Any], Callable[[], Awaitable[Dict[str, Any]]], Callable[[Dict[str, Any]], Awaitable[None]]],
    Awaitable[None],
]


@dataclass(frozen=True)
class BearerAuthConfig:
    token: str = field(repr=False)

    @classmethod
    def from_environment(cls) -> "BearerAuthConfig":
        value = os.environ.get(MCP_BEARER_ENV, "")
        try:
            encoded = value.encode("ascii")
        except UnicodeEncodeError:
            encoded = b""
        if (
            not 32 <= len(encoded) <= 256
            or any(byte <= 32 or byte == 127 for byte in encoded)
        ):
            raise ValueError(f"{MCP_BEARER_ENV} is unavailable or invalid")
        return cls(value)


class BearerAuthASGI:
    """Pure ASGI middleware; never logs or exposes the configured token."""

    def __init__(self, application: ASGIApp, config: BearerAuthConfig) -> None:
        self._application = application
        self._expected_sha256 = hashlib.sha256(
            ("Bearer " + config.token).encode("ascii")
        ).digest()

    @staticmethod
    def _authorization_values(scope: Dict[str, Any]) -> List[bytes]:
        headers: List[Tuple[bytes, bytes]] = scope.get("headers", [])
        return [
            value
            for name, value in headers
            if name.lower() == b"authorization"
        ]

    def _authorized(self, scope: Dict[str, Any]) -> bool:
        values = self._authorization_values(scope)
        if len(values) != 1:
            return False
        return hmac.compare_digest(
            hashlib.sha256(values[0]).digest(),
            self._expected_sha256,
        )

    @staticmethod
    async def _reject(
        send: Callable[[Dict[str, Any]], Awaitable[None]],
    ) -> None:
        body = b'{"error":"unauthorized"}'
        await send(
            {
                "type": "http.response.start",
                "status": 401,
                "headers": [
                    (b"content-type", b"application/json"),
                    (b"content-length", str(len(body)).encode("ascii")),
                    (b"cache-control", b"no-store"),
                    (b"www-authenticate", b"Bearer"),
                ],
            }
        )
        await send({"type": "http.response.body", "body": body})

    async def __call__(
        self,
        scope: Dict[str, Any],
        receive: Callable[[], Awaitable[Dict[str, Any]]],
        send: Callable[[Dict[str, Any]], Awaitable[None]],
    ) -> None:
        if scope.get("type") == "http" and not self._authorized(scope):
            await self._reject(send)
            return
        await self._application(scope, receive, send)
