from datetime import datetime
from typing import Any, Dict

from bson import ObjectId
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from app.models.subadmin import SubAdmin

from app.db.db import get_col
from app.models.admin import Admin, AdminLoginRequest, AdminLoginResponse, AdminOut
from app.utility.security import create_jwt, hash_password, verify_jwt, verify_password


router = APIRouter(prefix="/admin", tags=["admin"])
auth_scheme = HTTPBearer(auto_error=False)


def _admin_to_out(doc: Dict[str, Any]) -> AdminOut:
    return AdminOut(
        id=str(doc["_id"]),
        name=doc["name"],
        username=doc["username"],
        role=doc.get("role", "admin"),
        createdAt=doc.get("createdAt", datetime.utcnow()),
        updatedAt=doc.get("updatedAt", datetime.utcnow()),
    )


def _ensure_admin_token(credentials: HTTPAuthorizationCredentials = Depends(auth_scheme)) -> Dict[str, Any]:
    if not credentials:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authenticated")
    token = credentials.credentials
    ok, payload = verify_jwt(token)
    if not ok or not payload:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")
    if payload.get("role") != "admin":
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Not authorized")
    admins = get_col("admins")
    admin = admins.find_one({"_id": ObjectId(payload["sub"])})
    if not admin:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Admin not found")
    return admin


@router.post("/register", status_code=status.HTTP_201_CREATED)
def register_admin(body: Admin):
    admins = get_col("admins")
    if admins.find_one({"username": body.username.lower()}):
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Username already exists")
    now = datetime.utcnow()
    doc = {
        "name": body.name,
        "username": body.username.lower(),
        "password": hash_password(body.password),
        "role": body.role or "admin",
        "createdAt": now,
        "updatedAt": now,
        "timestamp": now,
    }
    res = admins.insert_one(doc)
    doc["_id"] = res.inserted_id
    return _admin_to_out(doc)


@router.post("/login", response_model=AdminLoginResponse)
def login_admin(body: AdminLoginRequest):
    admins = get_col("admins")
    subadmins = get_col("subadmins")
    doc = admins.find_one({"username": body.username.lower()})
    subadmin = subadmins.find_one({"username": body.username.lower()})
    if not doc and not subadmin:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid credentials")
    if doc and not verify_password(body.password, doc["password"]):
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid credentials")
    if subadmin and not verify_password(body.password, subadmin["password"]):
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid credentials")
    if doc:
        token = create_jwt({"sub": str(doc["_id"]), "role": doc.get("role", "admin"), "username": doc["username"]})
    elif subadmin:
        token = create_jwt({"sub": str(subadmin["_id"]), "role": subadmin.get("role", "subadmin"), "username": subadmin["username"]})
    else:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid credentials")
    return AdminLoginResponse(access_token=token)


@router.get("/me", response_model=AdminOut)
def get_me(admin: Dict[str, Any] = Depends(_ensure_admin_token)):
    return _admin_to_out(admin)


