from __future__ import annotations

from typing import Optional

from fastapi import Depends, HTTPException, status
from sqlalchemy.orm import Session
from sqlalchemy import select

from src.apps.admin.capabilities import AdminCap, get_role_capabilities
from src.apps.auth.utils.auth import get_current_superuser
from src.core.database import get_db


def _get_admin_user_role(db: Session, user_id: int):
    from src.apps.admin.models.admin_user_roles import AdminUserRole
    stmt = select(AdminUserRole).where(AdminUserRole.user_id == user_id)
    return db.execute(stmt).scalar_one_or_none()


def _get_assigned_merchant_ids(db: Session, user_id: int) -> list[int]:
    from src.apps.admin.models.agent_merchant_assignments import AgentMerchantAssignment
    stmt = select(AgentMerchantAssignment.merchant_id).where(
        AgentMerchantAssignment.agent_user_id == user_id,
        AgentMerchantAssignment.deleted_at.is_(None),
    )
    return list(db.execute(stmt).scalars().all())


def require_admin_capability(cap: AdminCap):
    """FastAPI dependency factory — raises 403 if caller's role lacks the capability."""
    async def _check(
        current_user=Depends(get_current_superuser),
        db: Session = Depends(get_db),
    ):
        user_role = _get_admin_user_role(db, current_user.id)
        if user_role is None:
            # Superusers without an explicit role assignment get full admin access
            return
        caps = get_role_capabilities(user_role.admin_role.slug)
        if cap not in caps:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Insufficient privileges.",
            )

    return _check


async def get_agent_merchant_ids(
    current_user=Depends(get_current_superuser),
    db: Session = Depends(get_db),
) -> Optional[list[int]]:
    """
    Returns None for non-agents (all merchants accessible).
    Returns list[int] for agents — only their assigned merchant IDs.
    """
    user_role = _get_admin_user_role(db, current_user.id)
    if user_role and user_role.admin_role.slug == "agent":
        return _get_assigned_merchant_ids(db, current_user.id)
    return None


async def get_current_admin_role_slug(
    current_user=Depends(get_current_superuser),
    db: Session = Depends(get_db),
) -> Optional[str]:
    """Returns the slug of the current admin user's role, or None if unassigned."""
    user_role = _get_admin_user_role(db, current_user.id)
    if user_role:
        return user_role.admin_role.slug
    return None
