from fastapi import Depends, HTTPException, Header, Request, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.orm import Session
from app.models.database import get_db
from app.models.client import Client
from app.security.auth import verify_api_key, decode_token
from app.config import settings

SESSION_COOKIE_NAME = "mt2mx_session"

bearer_scheme = HTTPBearer()


def get_current_client(
    x_api_key: str = Header(alias="X-API-Key"),
    db: Session = Depends(get_db),
) -> Client:
    client = db.query(Client).filter(
        Client.active == True,  # noqa: E712
        Client.deleted_at == None,  # noqa: E711
    ).all()

    for c in client:
        if verify_api_key(x_api_key, c.api_key_hash):
            return c

    raise HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="API Key inválida o cliente inactivo",
    )


def get_jwt_client(
    credentials: HTTPAuthorizationCredentials = Depends(bearer_scheme),
    db: Session = Depends(get_db),
) -> Client:
    payload = decode_token(credentials.credentials)
    if payload.get("type") != "api":
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Token inválido para este endpoint",
        )
    client_id = payload.get("sub")

    client = db.query(Client).filter(
        Client.id == client_id,
        Client.active == True,  # noqa: E712
        Client.deleted_at == None,  # noqa: E711
    ).first()

    if not client:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Cliente no encontrado o inactivo",
        )
    return client


def get_session_client(
    request: Request,
    db: Session = Depends(get_db),
) -> Client:
    token = request.cookies.get(SESSION_COOKIE_NAME)
    if not token:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="No hay sesión activa")

    payload = decode_token(token)
    if payload.get("type") != "session":
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Sesión inválida")
    client_id = payload.get("sub")

    client = db.query(Client).filter(
        Client.id == client_id,
        Client.active == True,  # noqa: E712
        Client.deleted_at == None,  # noqa: E711
    ).first()

    if not client:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Cliente no encontrado o inactivo")
    return client


def decode_purpose_token(token: str, expected_purpose: str) -> str:
    """Decodifica un token de un solo propósito y devuelve el client_id, o lanza 401/400."""
    payload = decode_token(token)
    if payload.get("type") != expected_purpose:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Token inválido o de otro tipo")
    client_id = payload.get("sub")
    if not client_id:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Token inválido")
    return client_id


def verify_admin(x_admin_secret: str = Header(alias="X-Admin-Secret")) -> bool:
    if x_admin_secret != settings.ADMIN_SECRET:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Admin secret inválido",
        )
    return True
