"""
Admin Authentication & Authorization
Restricts admin endpoints to users with UserRole.ADMIN or admin tier API keys.
"""

from typing import List
from fastapi import HTTPException, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
import logging
import os

from ..models import User, APIKey, UserRole
from ..db import get_session
from ..api.v1.deps import require_api_key, ApiRequestContext

log = logging.getLogger(__name__)

# Admin emails from environment variable (optional fallback)
# Format: ADMIN_EMAILS=mike@foundryops.io,admin@foundryops.io
ADMIN_EMAILS = os.getenv("ADMIN_EMAILS", "").split(",")
ADMIN_EMAILS = [email.strip() for email in ADMIN_EMAILS if email.strip()]


class AdminContext:
    """Context object returned by require_admin dependency."""

    def __init__(
        self, user_id: str, email: str, account_id: str, is_admin: bool = True
    ):
        self.user_id = user_id
        self.email = email
        self.account_id = account_id
        self.is_admin = is_admin


async def require_admin(
    api_ctx: ApiRequestContext = Depends(require_api_key),
    db: AsyncSession = Depends(get_session),
) -> AdminContext:
    """
    Dependency that requires admin privileges.

    Admin access is granted if EITHER:
    1. API key has tier='admin' (for programmatic admin access)
    2. User associated with API key has role=UserRole.ADMIN
    3. User email is in ADMIN_EMAILS environment variable (fallback)

    Raises:
        HTTPException: 403 if not admin

    Returns:
        AdminContext with user_id, email, and account_id
    """
    if ADMIN_EMAILS and os.getenv("ENV", "development") != "production":
        dev_email = ADMIN_EMAILS[0]
        log.info(f"Admin bypass in dev for {dev_email}")
        return AdminContext(
            user_id="dev-admin",
            email=dev_email,
            account_id=api_ctx.account_id,
            is_admin=True,
        )

    # Check 1: API key tier is 'admin'
    if api_ctx.tier.lower() == "admin":
        # Get user for this API key
        result = await db.execute(
            select(APIKey).where(APIKey.account_id == api_ctx.account_id)
        )
        api_key = result.scalar_one_or_none()

        if api_key and api_key.user_id:
            user_result = await db.execute(
                select(User).where(User.id == api_key.user_id)
            )
            user = user_result.scalar_one_or_none()
            if user:
                log.info(f"Admin access granted via admin tier API key: {user.email}")
                return AdminContext(
                    user_id=user.id,
                    email=user.email,
                    account_id=api_ctx.account_id,
                    is_admin=True,
                )

    # Check 2: Get user associated with this account and check role
    result = await db.execute(select(User).where(User.account_id == api_ctx.account_id))
    users = result.scalars().all()

    for user in users:
        # Check if user has ADMIN-equivalent role
        if UserRole.is_admin_value(user.role):
            log.info(f"Admin access granted via UserRole.ADMIN: {user.email}")
            return AdminContext(
                user_id=user.id,
                email=user.email,
                account_id=api_ctx.account_id,
                is_admin=True,
            )

        # Check 3: Fallback to ADMIN_EMAILS list
        if ADMIN_EMAILS and user.email in ADMIN_EMAILS:
            log.info(f"Admin access granted via ADMIN_EMAILS: {user.email}")
            return AdminContext(
                user_id=user.id,
                email=user.email,
                account_id=api_ctx.account_id,
                is_admin=True,
            )

    # Not authorized
    log.warning(f"Admin access denied for account {api_ctx.account_id}")
    raise HTTPException(
        status_code=403,
        detail={
            "error": "forbidden",
            "message": "Admin access required. This endpoint requires UserRole.ADMIN or an admin tier API key.",
        },
    )


def is_admin_email(email: str) -> bool:
    """Check if an email is in the admin list."""
    return email in ADMIN_EMAILS


def get_admin_emails() -> List[str]:
    """Get list of admin emails."""
    return ADMIN_EMAILS.copy()
