"""
Require a valid JWT for all /api/v1 routes except an explicit public allowlist.
Closes gaps where individual endpoints had auth removed for development.
"""
from __future__ import annotations

import re
from typing import FrozenSet, Tuple

from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.responses import JSONResponse

from app.core.config import settings
from app.core.security import verify_token

# Exact paths (no trailing slash variants)
_PUBLIC_EXACT: FrozenSet[str] = frozenset({
    "/api/v1/auth/login-json",
    "/api/v1/auth/login-direct",
    "/api/v1/auth/login-config",
    "/api/v1/auth/login-workspace",
    "/api/v1/auth/login-branches",
    "/api/v1/auth/login-branches/health",
    "/api/v1/companies/register",
    "/api/v1/companies/register-full",
    "/api/v1/companies/check-setup",
    "/api/v1/licensing/validate",
    "/api/v1/licensing/verify-setup",
    "/api/v1/licensing/claim-setup",
    "/api/v1/licensing/provision-cloud-mirror",
    "/api/v1/licensing/nodes/register",
    "/api/v1/licensing/nodes/heartbeat",
    "/api/v1/sync/ingest",
    "/api/v1/installer/local",
    "/api/v1/platform/auth/login",
    "/api/v1/platform/auth/configured",
})

# Prefixes that stay public (marketing, setup, licensing admin from separate secret)
_PUBLIC_PREFIXES: Tuple[str, ...] = (
    "/api/v1/companies/lookup/",
    "/api/v1/installer/download/",
)

_PUBLIC_PATTERNS: Tuple[re.Pattern, ...] = (
    re.compile(r"^/api/v1/auth/login$"),
    re.compile(r"^/api/v1/auth/login-test$"),
)


def _is_public_api_path(path: str) -> bool:
    if path in _PUBLIC_EXACT:
        return True
    if any(path.startswith(p) for p in _PUBLIC_PREFIXES):
        return True
    return any(pat.match(path) for pat in _PUBLIC_PATTERNS)


def _extract_bearer(request: Request) -> str | None:
    auth = request.headers.get("authorization") or ""
    if auth.lower().startswith("bearer "):
        return auth[7:].strip()
    return None


class ApiAuthMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        path = request.url.path

        if request.method == "OPTIONS":
            return await call_next(request)

        if not path.startswith("/api/v1"):
            return await call_next(request)

        if _is_public_api_path(path):
            return await call_next(request)

        # Refresh re-issues tokens — still requires current valid JWT
        if path == "/api/v1/auth/refresh":
            token = _extract_bearer(request)
            if not token or not verify_token(token):
                return JSONResponse(
                    status_code=401,
                    content={"success": False, "error": "unauthorized", "message": "Valid bearer token required"},
                )
            return await call_next(request)

        token = _extract_bearer(request)
        if not token:
            return JSONResponse(
                status_code=401,
                content={
                    "success": False,
                    "error": "unauthorized",
                    "message": "Authentication required",
                    "path": path,
                },
            )

        payload = verify_token(token)
        if not payload:
            return JSONResponse(
                status_code=401,
                content={"success": False, "error": "unauthorized", "message": "Invalid or expired token"},
            )

        is_platform = payload.get("platform_admin") is True
        is_platform_route = path.startswith("/api/v1/platform")

        if is_platform and not is_platform_route:
            return JSONResponse(
                status_code=403,
                content={
                    "success": False,
                    "error": "forbidden",
                    "message": "Platform operator token cannot access tenant APIs",
                },
            )
        if is_platform_route and not is_platform:
            return JSONResponse(
                status_code=403,
                content={
                    "success": False,
                    "error": "forbidden",
                    "message": "Platform operator authentication required",
                },
            )

        request.state.auth_payload = payload
        return await call_next(request)
