"""FastAPI dependencies: user, org context, upstream clients."""

from __future__ import annotations

import uuid
from typing import Annotated

import jwt
from fastapi import Depends, Header, HTTPException, Request, status
from sqlalchemy.ext.asyncio import AsyncSession

from aif_platform.server.auth.jwt_tokens import decode_access_token
from aif_platform.server.db.connection import get_db
from aif_platform.server.infra.upstream import EdaClient, NormbaseClient
from aif_platform.server.models.persistence import PlatformUser
from aif_platform.server.services.auth_service import get_user_by_id
from aif_platform.server.services.org_service import resolve_org_id_for_user


def get_normbase_client(request: Request) -> NormbaseClient:
    return request.app.state.normbase_client


def get_eda_client(request: Request) -> EdaClient:
    return request.app.state.eda_client


async def get_current_user(
    authorization: Annotated[str | None, Header()] = None,
    db: AsyncSession = Depends(get_db),
) -> PlatformUser:
    if not authorization or not authorization.lower().startswith("bearer "):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Missing bearer token.",
        )
    raw = authorization[7:].strip()
    try:
        payload = decode_access_token(raw)
    except jwt.PyJWTError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid or expired token.",
        ) from None
    try:
        uid = uuid.UUID(str(payload.get("sub")))
    except (TypeError, ValueError):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid token subject.",
        ) from None
    user = await get_user_by_id(db, uid)
    if not user or not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="User not found or inactive.",
        )
    return user


async def get_org_context(
    user: Annotated[PlatformUser, Depends(get_current_user)],
    db: AsyncSession = Depends(get_db),
    x_aif_org_id: Annotated[str | None, Header(alias="X-AIF-Org-Id")] = None,
) -> tuple[PlatformUser, uuid.UUID]:
    requested: uuid.UUID | None = None
    if x_aif_org_id:
        try:
            requested = uuid.UUID(x_aif_org_id.strip())
        except ValueError:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Invalid X-AIF-Org-Id.",
            ) from None
    org_id = await resolve_org_id_for_user(
        db,
        user_id=user.id,
        requested_org_id=requested,
    )
    return user, org_id


async def require_platform_admin(
    user: Annotated[PlatformUser, Depends(get_current_user)],
) -> PlatformUser:
    if not user.is_platform_admin:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Platform administrator required.",
        )
    return user
