"""Admin endpoints — canary management, fallback control, validation stats."""

from __future__ import annotations

from typing import Annotated, Any, Literal

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

from hive_compute.config import get_settings
from hive_compute.coordinator.billing import get_billing_items, get_partner_usage
from hive_compute.coordinator.canaries import add_canary, compute_transcript_similarity, get_random_canary
from hive_compute.coordinator.database import get_db_ctx
from hive_compute.coordinator.fallback import (
    check_and_trigger_fallback,
    complete_fallback,
    get_fallback_stats,
)
from hive_compute.coordinator.manager_auth import record_manager_action, require_manager_admin
from hive_compute.coordinator.merger import merge_job_shards
from hive_compute.coordinator.partners import (
    ACTIVE_PARTNER_STATUS,
    INACTIVE_PARTNER_STATUS,
    create_partner,
    list_partners,
    update_partner_budget,
    update_partner_status,
)
from hive_compute.coordinator.payouts import get_worker_earnings, release_held_payouts, reverse_payout
from hive_compute.coordinator.scheduler import describe_worker_benchmark_context
from hive_compute.coordinator.webhooks import replay_webhook

router = APIRouter(tags=["admin"])
ManagerAdmin = Annotated[dict[str, Any], Depends(require_manager_admin)]


# --- Canary management ---


class CanaryCreateRequest(BaseModel):
    audio_url: str
    expected_transcript: str
    language: str = "en"
    duration_seconds: float = 30.0
    difficulty: str = Field(default="normal", pattern="^(easy|normal|hard)$")


class FallbackCompleteRequest(BaseModel):
    transcript: str
    provider: str = "cloud"


@router.post("/admin/canaries")
def create_canary(req: CanaryCreateRequest, _admin: ManagerAdmin):
    """Add a known-answer audio clip to the canary corpus."""
    canary_id = add_canary(
        audio_url=req.audio_url,
        expected_transcript=req.expected_transcript,
        language=req.language,
        duration_seconds=req.duration_seconds,
        difficulty=req.difficulty,
    )
    record_manager_action(_admin, "canary_create", f"canary_id={canary_id}")
    return {"canary_id": canary_id, "message": "Canary added"}


@router.get("/admin/canaries")
def list_canaries(_admin: ManagerAdmin):
    """List all canaries in the corpus."""
    with get_db_ctx() as db:
        rows = db.execute(
            "SELECT canary_id, audio_url, language, duration_seconds, difficulty, created_at FROM canary_corpus"
        ).fetchall()

    return {
        "canaries": [
            {
                "canary_id": row["canary_id"],
                "audio_url": row["audio_url"],
                "language": row["language"],
                "duration_seconds": row["duration_seconds"],
                "difficulty": row["difficulty"],
                "created_at": row["created_at"],
            }
            for row in rows
        ],
        "total": len(rows),
    }


@router.get("/admin/canaries/sample")
def sample_canary(_admin: ManagerAdmin, language: str = "en"):
    """Get a random canary from the corpus (for testing)."""
    canary = get_random_canary(language)
    if not canary:
        return JSONResponse(status_code=404, content={"error": "No canaries available"})
    return canary


# --- Fallback management ---


@router.post("/admin/fallback/{shard_id}/trigger")
def trigger_fallback(shard_id: str, _admin: ManagerAdmin):
    """Manually trigger cloud fallback for a shard."""
    result = check_and_trigger_fallback(shard_id)
    if not result:
        # Force it even if heuristic says no
        from hive_compute.coordinator.fallback import create_fallback_attempt

        result = create_fallback_attempt(shard_id)

    if not result:
        return JSONResponse(status_code=404, content={"error": "Shard not found"})
    return result


@router.post("/admin/fallback/{shard_id}/complete")
def complete_fallback_result(
    shard_id: str,
    req: FallbackCompleteRequest,
    _admin: ManagerAdmin,
):
    """Submit the result of a cloud fallback transcription."""
    result = complete_fallback(shard_id, req.transcript, req.provider)
    if "error" in result:
        return JSONResponse(status_code=400, content=result)

    # Trigger merge now that fallback resolved the shard
    merge_job_shards(result["job_id"])

    return result


@router.get("/admin/fallback/stats")
def fallback_statistics(_admin: ManagerAdmin):
    """Get fallback usage statistics."""
    return get_fallback_stats()


# --- Validation stats ---


@router.get("/admin/validations")
def list_validations(
    _admin: ManagerAdmin,
    worker_id: str | None = None,
    validation_type: str | None = None,
    limit: int = 50,
):
    """List validation results with optional filters."""
    with get_db_ctx() as db:
        query = "SELECT * FROM validation_results WHERE 1=1"
        params: list = []

        if worker_id:
            query += " AND worker_id = ?"
            params.append(worker_id)
        if validation_type:
            query += " AND validation_type = ?"
            params.append(validation_type)

        query += " ORDER BY created_at DESC LIMIT ?"
        params.append(limit)

        rows = db.execute(query, params).fetchall()

    return {
        "validations": [
            {
                "validation_id": row["validation_id"],
                "shard_id": row["shard_id"],
                "job_id": row["job_id"],
                "worker_id": row["worker_id"],
                "validation_type": row["validation_type"],
                "similarity_score": row["similarity_score"],
                "passed": bool(row["passed"]),
                "detail": row["detail"],
                "created_at": row["created_at"],
            }
            for row in rows
        ],
        "total": len(rows),
    }


@router.post("/admin/validate/compare")
def compare_transcripts(
    expected: str,
    actual: str,
    _admin: ManagerAdmin,
):
    """Utility: compare two transcripts and get similarity score."""
    from hive_compute.config import get_settings
    threshold = get_settings().validated_canary_threshold()
    score = compute_transcript_similarity(expected, actual)
    return {"similarity": round(score, 4), "passed": score >= threshold, "threshold": threshold}


# --- Partner management ---


class PartnerCreateRequest(BaseModel):
    name: str
    rate_per_minute: float = 0.006
    callback_url: str | None = None
    monthly_budget_cents: int | None = Field(default=None, ge=0)
    terms_acknowledged: Literal[True] = Field(
        description="Manager must confirm the client agreed to the beta Terms of Service before issuing an API key.",
    )


class PartnerBudgetUpdateRequest(BaseModel):
    monthly_budget_cents: int | None = Field(default=None, ge=0)


class PartnerStatusUpdateRequest(BaseModel):
    status: str = Field(pattern=f"^({ACTIVE_PARTNER_STATUS}|{INACTIVE_PARTNER_STATUS})$")


@router.get("/admin/config/quality")
def get_quality_config(_admin: ManagerAdmin):
    """Show the effective quality routing and billing configuration."""
    settings = get_settings()
    quality_tiers = settings.get_quality_tiers()
    summary = settings.get_quality_settings_summary()
    return {
        "quality_tiers": quality_tiers,
        "default_quality": "balanced",
        "model_map": {quality: summary["quality_model_map"][quality] for quality in quality_tiers},
        "billing_multipliers": {quality: summary["billing_quality_multipliers"][quality] for quality in quality_tiers},
    }


@router.post("/admin/partners")
def create_partner_endpoint(req: PartnerCreateRequest, _admin: ManagerAdmin):
    """Create a new partner account. Returns the API key (only shown once)."""
    try:
        result = create_partner(req.name, req.rate_per_minute, req.callback_url, req.monthly_budget_cents)
    except ValueError as exc:
        return JSONResponse(status_code=422, content={"error": str(exc)})
    record_manager_action(_admin, "partner_create", f"partner_id={result['partner_id']}, name={req.name}")
    return result


@router.get("/admin/partners")
def list_partners_endpoint(_admin: ManagerAdmin):
    """List all partner accounts."""
    return {"partners": list_partners()}


@router.get("/admin/workers/{worker_id}/benchmark-context")
def get_worker_benchmark_context(worker_id: str, _admin: ManagerAdmin):
    """Explain benchmark coverage for pending work from this worker's perspective."""
    context = describe_worker_benchmark_context(worker_id)
    if not context:
        return JSONResponse(status_code=404, content={"error": "Worker not found"})
    return context


@router.post("/admin/partners/{partner_id}/status")
def update_partner_status_endpoint(
    partner_id: str,
    req: PartnerStatusUpdateRequest,
    _admin: ManagerAdmin,
):
    """Activate or suspend a partner account."""
    partner = update_partner_status(partner_id, req.status)
    if not partner:
        return JSONResponse(status_code=404, content={"error": "Partner not found"})

    record_manager_action(_admin, "partner_status_update", f"partner_id={partner_id}, status={req.status}")
    return partner


@router.post("/admin/partners/{partner_id}/budget")
def update_partner_budget_endpoint(
    partner_id: str,
    req: PartnerBudgetUpdateRequest,
    _admin: ManagerAdmin,
):
    """Update a partner's monthly budget cap."""
    partner = update_partner_budget(partner_id, req.monthly_budget_cents)
    if not partner:
        return JSONResponse(status_code=404, content={"error": "Partner not found"})

    record_manager_action(
        _admin,
        "partner_budget_update",
        f"partner_id={partner_id}, monthly_budget_cents={req.monthly_budget_cents}",
    )
    return partner


# --- Billing ---


@router.get("/admin/billing/{partner_id}")
def get_billing(
    partner_id: str,
    _admin: ManagerAdmin,
    period: str | None = None,
):
    """Get billing summary for a partner."""
    return get_partner_usage(partner_id, period)


@router.get("/admin/billing/{partner_id}/items")
def get_billing_line_items(
    partner_id: str,
    _admin: ManagerAdmin,
    limit: int = 50,
    offset: int = 0,
):
    """Get billing line items for a partner."""
    items = get_billing_items(partner_id, limit, offset)
    return {"items": items, "total": len(items)}


# --- Payouts ---


@router.get("/admin/payouts/{worker_id}")
def get_earnings(worker_id: str, _admin: ManagerAdmin):
    """Get earnings summary for a worker."""
    return get_worker_earnings(worker_id)


@router.post("/admin/payouts/release")
def release_payouts(_admin: ManagerAdmin):
    """Release all held payouts that have passed their hold period."""
    released = release_held_payouts()
    record_manager_action(_admin, "payout_release", f"released={released}")
    return {"released": released}


@router.post("/admin/payouts/{payout_id}/reverse")
def reverse_payout_endpoint(
    payout_id: int,
    _admin: ManagerAdmin,
    reason: str = "manual",
):
    """Reverse a payout."""
    success = reverse_payout(payout_id, reason)
    if not success:
        return JSONResponse(status_code=404, content={"error": "Payout not found or already reversed"})
    return {"reversed": True}


# --- Webhook management ---


@router.post("/admin/webhooks/{job_id}/replay")
def replay_webhook_endpoint(job_id: str, _admin: ManagerAdmin):
    """Replay a dead-letter webhook."""
    success = replay_webhook(job_id)
    if not success:
        return JSONResponse(status_code=404, content={"error": "No webhook found for job"})
    return {"replayed": True}


@router.get("/admin/webhooks/dead-letter")
def get_dead_letters(_admin: ManagerAdmin):
    """List all dead-letter webhook deliveries."""
    with get_db_ctx() as db:
        rows = db.execute(
            """
            SELECT job_id, target_url, attempts, last_error, created_at
            FROM webhook_deliveries WHERE status = 'dead_letter'
            ORDER BY created_at DESC
            """
        ).fetchall()

    return {
        "dead_letters": [
            {
                "job_id": row["job_id"],
                "target_url": row["target_url"],
                "attempts": row["attempts"],
                "last_error": row["last_error"],
                "created_at": row["created_at"],
            }
            for row in rows
        ],
        "total": len(rows),
    }
