"""Hosted manager UI APIs and public config endpoints."""

from __future__ import annotations

from typing import Annotated, Any

from fastapi import APIRouter, Depends, Request, Response
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field

from hive_compute.config import get_settings
from hive_compute.coordinator.abuse_events import (
    get_abuse_event,
    list_abuse_events,
    review_abuse_event,
)
from hive_compute.coordinator.database import get_db_ctx
from hive_compute.coordinator.enrollment import (
    create_enrollment_token,
    list_enrollment_tokens,
    revoke_enrollment_token,
)
from hive_compute.coordinator.manager_api_models import (
    ManagerConfigResponse,
    ManagerOverviewEventResponse,
    ManagerOverviewJobResponse,
    ManagerOverviewResponse,
    ManagerOverviewTotalsResponse,
    ManagerPartnerBalanceResponse,
    ManagerSessionResponse,
    build_manager_session_response,
)
from hive_compute.coordinator.manager_auth import (
    begin_bootstrap,
    begin_login,
    begin_recovery_registration,
    clear_session_cookie,
    count_admin_users,
    finish_bootstrap,
    finish_login,
    finish_recovery_registration,
    get_current_admin,
    get_manager_config,
    list_admin_audit,
    record_manager_action,
    regenerate_recovery_codes,
    require_manager_admin,
    revoke_session,
    set_session_cookie,
)
from hive_compute.coordinator.payouts import record_payout_disbursement

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

ManagerAdmin = Annotated[dict[str, Any], Depends(require_manager_admin)]


class BootstrapStartRequest(BaseModel):
    username: str = Field(min_length=1, max_length=64, pattern=r"^[a-zA-Z0-9._-]+$")
    display_name: str | None = Field(default=None, max_length=120)
    bootstrap_secret: str = Field(min_length=1)


class PasskeyFinishRequest(BaseModel):
    challenge_id: str = Field(min_length=1)
    credential: dict[str, Any]


class LoginStartRequest(BaseModel):
    username: str = Field(min_length=1, max_length=64, pattern=r"^[a-zA-Z0-9._-]+$")


class EnrollmentTokenCreateRequest(BaseModel):
    label: str | None = Field(default=None, max_length=120)
    ttl_minutes: int = Field(default=60, ge=1, le=24 * 60)
    max_uses: int = Field(default=1, ge=1, le=25)


class RecoveryStartRequest(BaseModel):
    username: str = Field(min_length=1, max_length=64, pattern=r"^[a-zA-Z0-9._-]+$")
    recovery_code: str = Field(min_length=1, max_length=64)


class RecoveryCodeRegenerateRequest(BaseModel):
    count: int = Field(default=8, ge=4, le=12)


class PayoutDisbursementRequest(BaseModel):
    worker_id: str = Field(min_length=1, max_length=128)
    amount_usd: float = Field(gt=0)
    note: str | None = Field(default=None, max_length=500)


class AbuseEventReviewRequest(BaseModel):
    resolution: str = Field(min_length=1, max_length=500)
    action: str = Field(default="none", pattern=r"^(none|revoke_worker_token)$")


@router.get("/config", response_model=ManagerConfigResponse)
def manager_config():
    return get_manager_config()


@router.get("/session", response_model=ManagerSessionResponse)
def manager_session(request: Request):
    admin = get_current_admin(request)
    return build_manager_session_response(admin, has_admins=count_admin_users() > 0)


@router.post("/bootstrap/start")
def manager_bootstrap_start(req: BootstrapStartRequest):
    return begin_bootstrap(req.username, req.display_name, req.bootstrap_secret)


@router.post("/bootstrap/finish")
def manager_bootstrap_finish(req: PasskeyFinishRequest, request: Request, response: Response):
    admin, session_token = finish_bootstrap(
        challenge_id=req.challenge_id,
        credential=req.credential,
        user_agent=request.headers.get("user-agent"),
    )
    set_session_cookie(response, session_token)
    return {"authenticated": True, "admin": admin}


@router.post("/login/start")
def manager_login_start(req: LoginStartRequest):
    return begin_login(req.username)


@router.post("/login/finish")
def manager_login_finish(req: PasskeyFinishRequest, request: Request, response: Response):
    admin, session_token = finish_login(
        challenge_id=req.challenge_id,
        credential=req.credential,
        user_agent=request.headers.get("user-agent"),
    )
    set_session_cookie(response, session_token)
    return {"authenticated": True, "admin": admin}


@router.post("/recovery/start")
def manager_recovery_start(req: RecoveryStartRequest):
    return begin_recovery_registration(req.username, req.recovery_code)


@router.post("/recovery/finish")
def manager_recovery_finish(req: PasskeyFinishRequest, request: Request, response: Response):
    admin, session_value = finish_recovery_registration(
        challenge_id=req.challenge_id,
        credential=req.credential,
        user_agent=request.headers.get("user-agent"),
    )
    set_session_cookie(response, session_value)
    return {"authenticated": True, "admin": admin}


@router.post("/logout")
def manager_logout(request: Request, response: Response):
    revoke_session(request)
    clear_session_cookie(response)
    return {"authenticated": False}


@router.get("/overview", response_model=ManagerOverviewResponse)
def manager_overview(_admin: ManagerAdmin):
    with get_db_ctx() as db:
        job_counts = db.execute(
            """
            SELECT status, COUNT(*) as cnt
            FROM jobs
            GROUP BY status
            """
        ).fetchall()
        worker_counts = db.execute(
            """
            SELECT status, COUNT(*) as cnt
            FROM workers
            GROUP BY status
            """
        ).fetchall()
        totals = {
            "partners": db.execute("SELECT COUNT(*) as cnt FROM partners").fetchone()["cnt"],
            "admins": db.execute("SELECT COUNT(*) as cnt FROM admin_users").fetchone()["cnt"],
            "passkeys": db.execute("SELECT COUNT(*) as cnt FROM admin_webauthn_credentials").fetchone()["cnt"],
        }
        recent_jobs = db.execute(
            """
            SELECT job_id, status, priority, created_at, completed_at
            FROM jobs
            ORDER BY created_at DESC
            LIMIT 8
            """
        ).fetchall()
        recent_events = db.execute(
            """
            SELECT event_type, actor, detail, created_at
            FROM job_events
            ORDER BY created_at DESC
            LIMIT 8
            """
        ).fetchall()
        partner_balances = db.execute(
            """
            SELECT partner_id, name, credits_usd
            FROM partners
            WHERE credits_usd IS NOT NULL
            ORDER BY credits_usd DESC, created_at DESC
            LIMIT 8
            """
        ).fetchall()

    return ManagerOverviewResponse(
        jobs={row["status"]: row["cnt"] for row in job_counts},
        workers={row["status"]: row["cnt"] for row in worker_counts},
        totals=ManagerOverviewTotalsResponse.model_validate(totals),
        recent_jobs=[
            ManagerOverviewJobResponse(
                job_id=row["job_id"],
                status=row["status"],
                priority=row["priority"],
                created_at=row["created_at"],
                completed_at=row["completed_at"],
            )
            for row in recent_jobs
        ],
        recent_events=[
            ManagerOverviewEventResponse(
                event_type=row["event_type"],
                actor=row["actor"],
                detail=row["detail"],
                created_at=row["created_at"],
            )
            for row in recent_events
        ],
        partner_balances=[
            ManagerPartnerBalanceResponse(
                partner_id=row["partner_id"],
                name=row["name"],
                credits_usd=round(float(row["credits_usd"]), 2),
            )
            for row in partner_balances
        ],
    )


@router.get("/quality-config")
def manager_quality_config(_admin: ManagerAdmin):
    settings = get_settings()
    return {
        "qualityModelMap": settings.get_quality_model_map(),
        "billingQualityMultipliers": settings.get_billing_quality_multipliers(),
        "knownQualities": ["fast", "balanced", "best"],
    }


@router.get("/enrollment-tokens")
def manager_enrollment_tokens(_admin: ManagerAdmin):
    tokens = list_enrollment_tokens()
    return {"tokens": tokens, "total": len(tokens)}


@router.post("/enrollment-tokens")
def manager_create_enrollment_token(req: EnrollmentTokenCreateRequest, admin: ManagerAdmin):
    return create_enrollment_token(
        admin_user_id=admin["adminUserId"],
        label=req.label,
        ttl_minutes=req.ttl_minutes,
        max_uses=req.max_uses,
    )


@router.post("/enrollment-tokens/{token_id}/revoke")
def manager_revoke_enrollment_token(token_id: str, admin: ManagerAdmin):
    if not revoke_enrollment_token(token_id):
        return {"revoked": False, "tokenId": token_id}
    record_manager_action(admin, "enrollment_token_revoke", f"token_id={token_id}")
    return {"revoked": True, "tokenId": token_id}


@router.post("/workers/{worker_id}/revoke-token")
def manager_revoke_worker_token(worker_id: str, admin: ManagerAdmin):
    with get_db_ctx() as db:
        result = db.execute(
            """
            UPDATE workers
            SET worker_token_revoked_at = datetime('now'),
                status = 'offline'
            WHERE worker_id = ? AND worker_token_revoked_at IS NULL
            """,
            (worker_id,),
        )
        if result.rowcount == 0:
            exists = db.execute("SELECT worker_id FROM workers WHERE worker_id = ?", (worker_id,)).fetchone()
            if not exists:
                return JSONResponse(status_code=404, content={"revoked": False, "workerId": worker_id})
            return {"revoked": False, "workerId": worker_id}

    record_manager_action(admin, "worker_token_revoke", f"worker_id={worker_id}")
    return {"revoked": True, "workerId": worker_id}


@router.post("/recovery-codes/regenerate")
def manager_regenerate_recovery_codes(req: RecoveryCodeRegenerateRequest, admin: ManagerAdmin):
    return regenerate_recovery_codes(admin["adminUserId"], count=req.count)


@router.post("/payouts/disburse")
def manager_disburse_payout(req: PayoutDisbursementRequest, admin: ManagerAdmin):
    event = record_payout_disbursement(req.worker_id, req.amount_usd, req.note)
    record_manager_action(
        admin,
        "payout_disburse",
        f"worker_id={req.worker_id}, amount_usd={req.amount_usd:.2f}",
    )
    return event


@router.get("/audit-log")
def manager_audit_log(_admin: ManagerAdmin):
    entries = list_admin_audit()
    return {"entries": entries, "total": len(entries)}


@router.get("/abuse-events")
def manager_abuse_events(_admin: ManagerAdmin, status: str | None = None, limit: int = 50):
    entries = list_abuse_events(limit=limit, status=status)
    return {"entries": entries, "total": len(entries)}


@router.post("/abuse-events/{abuse_event_id}/review")
def manager_review_abuse_event(abuse_event_id: int, req: AbuseEventReviewRequest, admin: ManagerAdmin):
    event = get_abuse_event(abuse_event_id)
    if not event:
        return JSONResponse(status_code=404, content={"error": "Abuse event not found"})

    action_detail = "no_action"
    if req.action == "revoke_worker_token":
        if event["subjectType"] != "worker":
            return JSONResponse(status_code=422, content={"error": "Only worker abuse events support token revocation"})
        with get_db_ctx() as db:
            result = db.execute(
                """
                UPDATE workers
                SET worker_token_revoked_at = datetime('now'),
                    status = 'offline'
                WHERE worker_id = ? AND worker_token_revoked_at IS NULL
                """,
                (event["subjectId"],),
            )
        action_detail = f"revoke_worker_token:{'applied' if result.rowcount else 'noop'}"

    reviewed = review_abuse_event(
        abuse_event_id,
        admin_user_id=admin["adminUserId"],
        resolution=req.resolution,
        review_action=req.action,
    )
    record_manager_action(
        admin,
        "abuse_event_review",
        f"event_id={abuse_event_id}, subject={event['subjectType']}:{event['subjectId']}, action={action_detail}",
    )
    return reviewed
