from __future__ import annotations

from datetime import UTC, datetime

from fastapi import Depends, HTTPException, Request, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from sqlalchemy.orm import Session

from app.core.database import get_db
from app.core.auth_context import ChatAccessScope, UserAuthContext
from app.core.security import decode_access_token
from app.models.admin import Admin
from app.models.sso import SsoClient
from app.models.user import User
from app.services.auth_service import AuthService

bearer_scheme = HTTPBearer(auto_error=True)


def get_current_token_payload(credentials: HTTPAuthorizationCredentials = Depends(bearer_scheme)) -> dict:
    payload = decode_access_token(credentials.credentials)
    if AuthService.is_token_revoked(payload):
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="登录已退出")
    return payload


def get_current_user_context(
    payload: dict = Depends(get_current_token_payload),
    db: Session = Depends(get_db),
) -> UserAuthContext:
    if payload.get("type") != "user":
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="当前凭证不是用户登录态")

    user_id = payload.get("sub")
    user = db.get(User, int(user_id)) if user_id else None
    if user is None or user.is_deleted:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="用户不存在")
    if user.status != 1:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="账号已禁用")
    now = datetime.now(UTC).replace(tzinfo=None)
    if user.effective_at and user.effective_at > now:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="账号尚未生效")
    if user.expired_at and user.expired_at < now:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="账号已过期")
    auth_source = str(payload.get("auth_source") or "direct")
    if auth_source == "direct":
        scope = ChatAccessScope.direct()
    elif auth_source == "sso":
        try:
            client_id = int(payload.get("sso_client_id"))
        except (TypeError, ValueError) as exc:
            raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="接入应用登录态无效") from exc
        client = db.get(SsoClient, client_id)
        if client is None or client.status != 1:
            raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="接入应用已停用")
        scope = ChatAccessScope(source_type="sso", source_client_id=client_id)
    else:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="登录来源无效")
    return UserAuthContext(user=user, chat_scope=scope)


def get_current_user(context: UserAuthContext = Depends(get_current_user_context)) -> User:
    return context.user


def get_current_admin(
    payload: dict = Depends(get_current_token_payload),
    db: Session = Depends(get_db),
) -> Admin:
    if payload.get("type") != "admin":
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="当前凭证不是管理员登录态")

    admin_id = payload.get("sub")
    admin = db.get(Admin, int(admin_id)) if admin_id else None
    if admin is None:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="管理员不存在")
    if admin.status != 1:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="管理员已禁用")
    return admin


def enforce_admin_access(
    request: Request,
    admin: Admin = Depends(get_current_admin),
) -> Admin:
    """Block first-login accounts and enforce permissions on every existing admin API."""
    from app.services.admin_permission_service import require_permission

    if admin.must_change_password:
        raise HTTPException(status_code=status.HTTP_428_PRECONDITION_REQUIRED, detail="首次登录请先修改初始密码")
    path = request.url.path.split("/admin/", 1)[-1].strip("/")
    method = request.method.upper()
    if path.startswith("dashboard"):
        permission = "dashboard.view"
    elif path.startswith("user/") and ("/entitlement" in path or path.startswith("user/entitlement")):
        permission = "entitlements.edit"
    elif path.startswith("entitlement/"):
        permission = "entitlements.view" if method == "GET" else "entitlements.edit"
    elif path.startswith("user/"):
        permission = "users.delete" if method == "DELETE" else ("users.view" if method == "GET" else ("users.create" if method == "POST" and (path in {"user", "user/import", "user/import/excel"}) else "users.edit"))
    elif path.startswith("knowledge"):
        permission = "knowledge.delete" if method == "DELETE" else ("knowledge.view" if method == "GET" else ("knowledge.publish" if path.endswith("open-status") or path.endswith("lifecycle") else "knowledge.edit"))
    elif path.startswith("prompt") or path.startswith("agent/"):
        permission = "prompt.view" if method == "GET" else "prompt.edit"
    elif path.startswith("model"):
        permission = "models.delete" if method == "DELETE" else ("models.view" if method == "GET" else "models.edit")
    elif path.startswith("content-generation"):
        permission = "content-generation.view" if method == "GET" else "content-generation.edit"
    elif path.startswith("config") or path.startswith("feishu/cache"):
        permission = "configs.view" if method == "GET" else "configs.edit"
    elif path.startswith("sso/"):
        permission = "sso.view" if method == "GET" else "sso.edit"
    elif path.startswith("retrieval-log"):
        permission = "retrievals.view" if method == "GET" else "configs.edit"
    elif path.startswith("attention"):
        permission = "attention.view" if method == "GET" else "attention.edit"
    else:
        permission = "records.view"
    require_permission(admin, permission)
    return admin
