from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from app.database import get_database
from app.repositories.agent_repository import get_agent_by_id
from app.utils.security import decode_access_token

security = HTTPBearer(auto_error=False)

async def get_current_agent(credentials: HTTPAuthorizationCredentials | None = Depends(security)) -> dict:
    """
    FastAPI dependency that validates Bearer JWT access token and resolves authenticated agent.
    Raises HTTP 401 Unauthorized if missing, invalid, or expired.
    """
    if not credentials or not credentials.credentials:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Authentication credentials were not provided",
            headers={"WWW-Authenticate": "Bearer"},
        )

    payload = decode_access_token(credentials.credentials)
    if not payload or not payload.get("sub"):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid or expired access token",
            headers={"WWW-Authenticate": "Bearer"},
        )

    agent_id = payload.get("sub")
    db = get_database()
    agent = await get_agent_by_id(db, agent_id)

    if not agent or agent.get("status") != "ACTIVE":
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Agent account is inactive or not found",
            headers={"WWW-Authenticate": "Bearer"},
        )

    # Return safe copy without passwordHash
    safe_agent = dict(agent)
    safe_agent.pop("passwordHash", None)
    return safe_agent

async def get_current_agent_optional(credentials: HTTPAuthorizationCredentials | None = Depends(security)) -> dict | None:
    """
    Optional authentication dependency.
    Returns safe agent dict if valid Bearer token is provided; returns None otherwise.
    """
    if not credentials or not credentials.credentials:
        return None

    payload = decode_access_token(credentials.credentials)
    if not payload or not payload.get("sub"):
        return None

    agent_id = payload.get("sub")
    db = get_database()
    agent = await get_agent_by_id(db, agent_id)

    if not agent or agent.get("status") != "ACTIVE":
        return None

    safe_agent = dict(agent)
    safe_agent.pop("passwordHash", None)
    return safe_agent

async def require_agent(current_agent: dict = Depends(get_current_agent)) -> dict:
    """
    Authorization dependency ensuring the caller is an active AGENT or ADMIN.
    """
    if current_agent.get("role") not in ("AGENT", "ADMIN"):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Agent authorization required for this action"
        )
    return current_agent

async def require_admin(current_agent: dict = Depends(get_current_agent)) -> dict:
    """
    Authorization dependency ensuring the caller has ADMIN role.
    Raises HTTP 403 Forbidden if user is not an ADMIN.
    """
    if current_agent.get("role") != "ADMIN":
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Admin role required for this action"
        )
    return current_agent
