from fastapi import Depends, Header, Query
from jose import JWTError
from sqlalchemy.orm import Session

from app.core.exceptions import ForbiddenError, UnauthorizedError, ValidationError
from app.core.security import decode_token
from app.db.session import get_db
from app.models.user import User
from app.schemas.user_context import CurrentUser

ROLE_SUPER_ADMIN = "super_admin"
ROLE_ADMIN = "admin"
ROLE_AGENT = "agent"


def get_current_user(
    authorization: str | None = Header(default=None),
    db: Session = Depends(get_db),
) -> CurrentUser:
    if not authorization or not authorization.startswith("Bearer "):
        raise UnauthorizedError("Missing or invalid authorization header")
    token = authorization.split(" ", 1)[1]
    try:
        payload = decode_token(token)
        if payload.get("type") != "access":
            raise UnauthorizedError("Invalid token type")
        user_id = int(payload["sub"])
    except (JWTError, KeyError, ValueError) as exc:
        raise UnauthorizedError("Invalid or expired token") from exc

    user = db.query(User).filter(User.id == user_id, User.deleted_at.is_(None), User.is_active.is_(True)).first()
    if not user:
        raise UnauthorizedError("User not found or inactive")

    return CurrentUser(
        id=user.id,
        email=user.email,
        full_name=user.full_name,
        role=user.role.value,
        agency_id=user.agency_id,
        agency_name=user.agency.name,
    )


def is_super_admin(user: CurrentUser) -> bool:
    return user.role == ROLE_SUPER_ADMIN


def is_agency_admin(user: CurrentUser) -> bool:
    return user.role == ROLE_ADMIN


def require_super_admin(current_user: CurrentUser = Depends(get_current_user)) -> CurrentUser:
    if not is_super_admin(current_user):
        raise ForbiddenError("Super admin access required")
    return current_user


def require_admin(current_user: CurrentUser = Depends(get_current_user)) -> CurrentUser:
    if current_user.role != ROLE_ADMIN:
        raise ForbiddenError("Admin access required")
    return current_user


def resolve_agency_id(
    current_user: CurrentUser,
    agency_id: int | None = None,
    *,
    required_for_super_admin: bool = True,
) -> int:
    if is_super_admin(current_user):
        if agency_id is None and required_for_super_admin:
            raise ValidationError("agency_id is required for this action")
        return agency_id if agency_id is not None else current_user.agency_id
    return current_user.agency_id


def scoped_agency_id(
    agency_id: int | None = Query(default=None),
    current_user: CurrentUser = Depends(get_current_user),
) -> int:
    return resolve_agency_id(current_user, agency_id)
