"""Admin API routes.

⚠️ AUTO-GENERATED BY PRISM (GENERATE_ONCE)
User management, whitelist CRUD, bootstrap endpoint.
"""

from __future__ import annotations

import logging
from typing import Annotated

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession

from pydantic import BaseModel

from {{ project_name }}.admin.admin_service import (
    add_whitelist_rule,
    count_users,
    delete_user,
    delete_whitelist_rule,
    get_user_by_id,
    list_users,
    list_whitelist_rules,
    set_user_active,
    update_user_roles,
    validate_signup_access,
)
from {{ project_name }}.admin.bootstrap_service import hash_bootstrap_token, is_token_expired
from {{ project_name }}.auth.password_service import hash_password
from {{ project_name }}.database import get_db
from {{ project_name }}.middleware.auth import CurrentActiveUser, require_roles
from {{ project_name }}.models.{{ user_model_snake }} import {{ user_model }}
from {{ project_name }}.schemas.admin import (
    AdminUserListResponse,
    AdminUserResponse,
    AdminUserUpdateRequest,
    BootstrapRequest,
    BootstrapResponse,
    WhitelistRuleCreateRequest,
    WhitelistRuleResponse,
)

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/admin", tags=["admin"])

AdminUser = Annotated[{{ user_model }}, Depends(require_roles("admin"))]


# ── User management ─────────────────────────────────────────────


@router.get("/users", response_model=AdminUserListResponse)
async def admin_list_users(
    current_user: AdminUser,
    db: Annotated[AsyncSession, Depends(get_db)],
    skip: int = 0,
    limit: int = 50,
) -> AdminUserListResponse:
    """List all users (admin only)."""
    users = await list_users(db, skip=skip, limit=limit)
    total = await count_users(db)
    return AdminUserListResponse(
        users=[AdminUserResponse.model_validate(u) for u in users],
        total=total,
        skip=skip,
        limit=limit,
    )


@router.get("/users/{user_id}", response_model=AdminUserResponse)
async def admin_get_user(
    user_id: int,
    current_user: AdminUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> AdminUserResponse:
    """Get user detail (admin only)."""
    user = await get_user_by_id(db, user_id)
    if not user:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
    return AdminUserResponse.model_validate(user)


@router.patch("/users/{user_id}", response_model=AdminUserResponse)
async def admin_update_user(
    user_id: int,
    body: AdminUserUpdateRequest,
    current_user: AdminUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> AdminUserResponse:
    """Update user (admin only)."""
    user = await get_user_by_id(db, user_id)
    if not user:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")

    if body.roles is not None:
        user = await update_user_roles(db, user_id, body.roles)
    if body.is_active is not None:
        user = await set_user_active(db, user_id, is_active=body.is_active)

    return AdminUserResponse.model_validate(user)


@router.delete("/users/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
async def admin_delete_user(
    user_id: int,
    current_user: AdminUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> None:
    """Delete user (admin only)."""
    if user_id == current_user.id:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Cannot delete your own account",
        )
    if not await delete_user(db, user_id):
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")


@router.post("/users/{user_id}/promote", response_model=AdminUserResponse)
async def admin_promote_user(
    user_id: int,
    current_user: AdminUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> AdminUserResponse:
    """Promote user to admin."""
    user = await get_user_by_id(db, user_id)
    if not user:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")

    roles = list(set(user.roles or []) | {"admin"})
    user = await update_user_roles(db, user_id, roles)
    return AdminUserResponse.model_validate(user)


@router.post("/users/{user_id}/demote", response_model=AdminUserResponse)
async def admin_demote_user(
    user_id: int,
    current_user: AdminUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> AdminUserResponse:
    """Remove admin role from user."""
    if user_id == current_user.id:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Cannot demote yourself",
        )
    user = await get_user_by_id(db, user_id)
    if not user:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")

    roles = [r for r in (user.roles or []) if r != "admin"]
    user = await update_user_roles(db, user_id, roles)
    return AdminUserResponse.model_validate(user)


# ── Invite ────────────────────────────────────────────────────────


class InviteRequest(BaseModel):
    email: str


@router.post("/invite")
async def admin_invite_user(
    body: InviteRequest,
    current_user: AdminUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> dict:
    """Send an invite email (admin only). Validates against whitelist first."""
    from {{ project_name }}.services.email_service import send_invite_email

    email = body.email.strip().lower()
    allowed = await validate_signup_access(email, db)
    if not allowed:
        domain = email.split("@")[1] if "@" in email else email
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Email not whitelisted. Add domain '{domain}' or email '{email}' to the whitelist.",
        )

    send_invite_email(email)
    return {"message": f"Invite sent to {email}"}


# ── Whitelist CRUD ───────────────────────────────────────────────


@router.get("/whitelist", response_model=list[WhitelistRuleResponse])
async def admin_list_whitelist(
    current_user: AdminUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> list[WhitelistRuleResponse]:
    """List whitelist rules (admin only)."""
    rules = await list_whitelist_rules(db)
    return [WhitelistRuleResponse.model_validate(r) for r in rules]


@router.post("/whitelist", response_model=WhitelistRuleResponse, status_code=status.HTTP_201_CREATED)
async def admin_add_whitelist_rule(
    body: WhitelistRuleCreateRequest,
    current_user: AdminUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> WhitelistRuleResponse:
    """Add a whitelist rule (admin only)."""
    rule = await add_whitelist_rule(
        db,
        rule_type=body.rule_type,
        value=body.value,
        created_by=current_user.{{ username_field }},
    )
    return WhitelistRuleResponse.model_validate(rule)


@router.delete("/whitelist/{rule_id}", status_code=status.HTTP_204_NO_CONTENT)
async def admin_delete_whitelist_rule(
    rule_id: int,
    current_user: AdminUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> None:
    """Delete a whitelist rule (admin only)."""
    if not await delete_whitelist_rule(db, rule_id):
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Rule not found")


# ── Bootstrap ────────────────────────────────────────────────────


@router.post("/bootstrap", response_model=BootstrapResponse)
async def bootstrap_admin(
    body: BootstrapRequest,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> BootstrapResponse:
    """Consume a bootstrap token to set up the first admin account.

    This endpoint is unauthenticated — it validates the one-time token
    generated by ``prism admin bootstrap``.
    """
    from sqlalchemy import select

    # Find user with matching bootstrap token
    hashed = hash_bootstrap_token(body.token)
    result = await db.execute(
        select({{ user_model }}).where({{ user_model }}.bootstrap_token == hashed)
    )
    user = result.scalar_one_or_none()

    if not user:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid or already-used bootstrap token.",
        )

    if user.bootstrap_token_created_at and is_token_expired(user.bootstrap_token_created_at):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Bootstrap token has expired.",
        )

    # Set password and consume token
    user.password_hash = hash_password(body.password)
    user.bootstrap_token = None
    user.bootstrap_token_created_at = None
    user.is_active = True
    user.email_verified = True
    await db.commit()
    await db.refresh(user)

    return BootstrapResponse(
        message="Admin account activated.",
        user=AdminUserResponse.model_validate(user),
    )
