"""Reject JWTs whose credential_version no longer matches the user (password change / reset)."""

from __future__ import annotations

import uuid
from typing import Awaitable, Callable

from fastapi import Request, Response
from starlette.responses import JSONResponse

from src.auth_jwt import decode_bearer_token, jwt_credential_version_from_payload
from src.initiative_db.engine import get_session, is_postgres_enabled
from src.initiative_db.models import User

# POST-only auth paths that accept requests without cv check (unauthenticated or pre-migration tokens).
_AUTH_PUBLIC: set[tuple[str, str]] = {
    ("/api/v1/auth/register", "POST"),
    ("/api/v1/auth/login", "POST"),
    ("/api/v1/auth/forgot-password", "POST"),
    ("/api/v1/auth/reset-password", "POST"),
    ("/api/v1/auth/verify-email", "POST"),
    ("/api/v1/auth/resend-verification", "POST"),
    ("/api/v1/auth/verify-otp", "POST"),
    ("/api/v1/auth/resend-otp", "POST"),
}


def _is_public_auth_path(path: str, method: str) -> bool:
    return (path, method.upper()) in _AUTH_PUBLIC


async def auth_credential_version_middleware(
    request: Request, call_next: Callable[[Request], Awaitable[Response]]
) -> Response:
    if not is_postgres_enabled():
        return await call_next(request)

    auth = request.headers.get("authorization")
    if not auth:
        return await call_next(request)

    path = request.url.path
    method = request.method.upper()
    if _is_public_auth_path(path, method):
        return await call_next(request)

    payload = decode_bearer_token(auth)
    if payload is None:
        return JSONResponse({"detail": "Token không hợp lệ."}, status_code=401)

    try:
        uid = uuid.UUID(str(payload["sub"]))
    except (KeyError, ValueError):
        return JSONResponse({"detail": "Token không hợp lệ."}, status_code=401)

    jwt_cv = jwt_credential_version_from_payload(payload)

    async with get_session() as session:
        user = await session.get(User, uid)
        if user is None or not user.is_active:
            return JSONResponse(
                {"detail": "Tài khoản không còn hiệu lực."},
                status_code=401,
            )
        db_cv = int(user.credential_version or 0)
        if jwt_cv != db_cv:
            return JSONResponse(
                {"detail": "Phiên đăng nhập hết hạn. Vui lòng đăng nhập lại."},
                status_code=401,
            )

    return await call_next(request)
