"""Quest system routes for agent token rewards.

Provides API endpoints for:
- Listing quests and their status
- Claiming quest rewards
- Getting quest leaderboard
- Quest progress tracking
"""

from __future__ import annotations

import logging
from typing import Any

from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse, JSONResponse
from pydantic import BaseModel

from dashboard.templating import templates
from timmy.quest_system import (
    QuestStatus,
    auto_evaluate_all_quests,
    claim_quest_reward,
    evaluate_quest_progress,
    get_active_quests,
    get_agent_quests_status,
    get_quest_definition,
    get_quest_leaderboard,
    load_quest_config,
)

logger = logging.getLogger(__name__)

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


class ClaimQuestRequest(BaseModel):
    """Request to claim a quest reward."""

    agent_id: str
    quest_id: str


class EvaluateQuestRequest(BaseModel):
    """Request to manually evaluate quest progress."""

    agent_id: str
    quest_id: str


# ---------------------------------------------------------------------------
# API Endpoints
# ---------------------------------------------------------------------------


@router.get("/api/definitions")
async def get_quest_definitions_api() -> JSONResponse:
    """Get all quest definitions.

    Returns:
        JSON list of all quest definitions with their criteria.
    """
    definitions = get_active_quests()
    return JSONResponse(
        {
            "quests": [
                {
                    "id": q.id,
                    "name": q.name,
                    "description": q.description,
                    "reward_tokens": q.reward_tokens,
                    "type": q.quest_type.value,
                    "repeatable": q.repeatable,
                    "cooldown_hours": q.cooldown_hours,
                    "criteria": q.criteria,
                }
                for q in definitions
            ]
        }
    )


@router.get("/api/status/{agent_id}")
async def get_agent_quest_status(agent_id: str) -> JSONResponse:
    """Get quest status for a specific agent.

    Returns:
        Complete quest status including progress, completion counts,
        and tokens earned.
    """
    status = get_agent_quests_status(agent_id)
    return JSONResponse(status)


@router.post("/api/claim")
async def claim_quest_reward_api(request: ClaimQuestRequest) -> JSONResponse:
    """Claim a quest reward for an agent.

    The quest must be completed but not yet claimed.
    """
    reward = claim_quest_reward(request.quest_id, request.agent_id)

    if not reward:
        return JSONResponse(
            {
                "success": False,
                "error": "Quest not completed, already claimed, or on cooldown",
            },
            status_code=400,
        )

    return JSONResponse(
        {
            "success": True,
            "reward": reward,
        }
    )


@router.post("/api/evaluate")
async def evaluate_quest_api(request: EvaluateQuestRequest) -> JSONResponse:
    """Manually evaluate quest progress with provided context.

    This is useful for testing or when the quest completion
    needs to be triggered manually.
    """
    quest = get_quest_definition(request.quest_id)
    if not quest:
        return JSONResponse(
            {"success": False, "error": "Quest not found"},
            status_code=404,
        )

    # Build evaluation context based on quest type
    context = await _build_evaluation_context(quest)

    progress = evaluate_quest_progress(request.quest_id, request.agent_id, context)

    if not progress:
        return JSONResponse(
            {"success": False, "error": "Failed to evaluate quest"},
            status_code=500,
        )

    # Auto-claim if completed
    reward = None
    if progress.status == QuestStatus.COMPLETED:
        reward = claim_quest_reward(request.quest_id, request.agent_id)

    return JSONResponse(
        {
            "success": True,
            "progress": progress.to_dict(),
            "reward": reward,
            "completed": progress.status == QuestStatus.COMPLETED,
        }
    )


@router.get("/api/leaderboard")
async def get_leaderboard_api() -> JSONResponse:
    """Get the quest completion leaderboard.

    Returns agents sorted by total tokens earned.
    """
    leaderboard = get_quest_leaderboard()
    return JSONResponse(
        {
            "leaderboard": leaderboard,
        }
    )


@router.post("/api/reload")
async def reload_quest_config_api() -> JSONResponse:
    """Reload quest configuration from quests.yaml.

    Useful for applying quest changes without restarting.
    """
    definitions, quest_settings = load_quest_config()
    return JSONResponse(
        {
            "success": True,
            "quests_loaded": len(definitions),
            "settings": quest_settings,
        }
    )


# ---------------------------------------------------------------------------
# Dashboard UI Endpoints
# ---------------------------------------------------------------------------


@router.get("", response_class=HTMLResponse)
async def quests_dashboard(request: Request) -> HTMLResponse:
    """Main quests dashboard page."""
    return templates.TemplateResponse(
        request,
        "quests.html",
        {"agent_id": "current_user"},
    )


@router.get("/panel/{agent_id}", response_class=HTMLResponse)
async def quests_panel(request: Request, agent_id: str) -> HTMLResponse:
    """Quest panel for HTMX partial updates."""
    status = get_agent_quests_status(agent_id)
    return templates.TemplateResponse(
        request,
        "partials/quests_panel.html",
        {
            "agent_id": agent_id,
            "quests": status["quests"],
            "total_tokens": status["total_tokens_earned"],
            "completed_count": status["total_quests_completed"],
        },
    )


# ---------------------------------------------------------------------------
# Internal Functions
# ---------------------------------------------------------------------------


async def _build_evaluation_context(quest) -> dict[str, Any]:
    """Build evaluation context for a quest based on its type."""
    context: dict[str, Any] = {}

    if quest.quest_type.value == "issue_count":
        # Fetch closed issues with relevant labels
        context["closed_issues"] = await _fetch_closed_issues(
            quest.criteria.get("issue_labels", [])
        )

    elif quest.quest_type.value == "issue_reduce":
        # Fetch current and previous issue counts
        labels = quest.criteria.get("issue_labels", [])
        context["current_issue_count"] = await _fetch_open_issue_count(labels)
        context["previous_issue_count"] = await _fetch_previous_issue_count(
            labels, quest.criteria.get("lookback_days", 7)
        )

    elif quest.quest_type.value == "daily_run":
        # Fetch Daily Run metrics
        metrics = await _fetch_daily_run_metrics()
        context["sessions_completed"] = metrics.get("sessions_completed", 0)

    return context


async def _fetch_closed_issues(labels: list[str]) -> list[dict]:
    """Fetch closed issues matching the given labels."""
    try:
        from dashboard.routes.daily_run import GiteaClient, _load_config

        config = _load_config()
        token = _get_gitea_token(config)
        client = GiteaClient(config, token)

        if not client.is_available():
            return []

        # Build label filter
        label_filter = ",".join(labels) if labels else ""

        issues = client.get_paginated(
            "issues",
            {"state": "closed", "labels": label_filter, "limit": 100},
        )

        return issues
    except Exception as exc:
        logger.debug("Failed to fetch closed issues: %s", exc)
        return []


async def _fetch_open_issue_count(labels: list[str]) -> int:
    """Fetch count of open issues with given labels."""
    try:
        from dashboard.routes.daily_run import GiteaClient, _load_config

        config = _load_config()
        token = _get_gitea_token(config)
        client = GiteaClient(config, token)

        if not client.is_available():
            return 0

        label_filter = ",".join(labels) if labels else ""

        issues = client.get_paginated(
            "issues",
            {"state": "open", "labels": label_filter, "limit": 100},
        )

        return len(issues)
    except Exception as exc:
        logger.debug("Failed to fetch open issue count: %s", exc)
        return 0


async def _fetch_previous_issue_count(labels: list[str], lookback_days: int) -> int:
    """Fetch previous issue count (simplified - uses current for now)."""
    # This is a simplified implementation
    # In production, you'd query historical data
    return await _fetch_open_issue_count(labels)


async def _fetch_daily_run_metrics() -> dict[str, Any]:
    """Fetch Daily Run metrics."""
    try:
        from dashboard.routes.daily_run import _get_metrics

        metrics = _get_metrics(lookback_days=7)
        if metrics:
            return {
                "sessions_completed": metrics.sessions_completed,
                "sessions_previous": metrics.sessions_previous,
            }
    except Exception as exc:
        logger.debug("Failed to fetch Daily Run metrics: %s", exc)

    return {"sessions_completed": 0, "sessions_previous": 0}


def _get_gitea_token(config: dict) -> str | None:
    """Get Gitea token from config."""
    if "token" in config:
        return config["token"]

    from pathlib import Path

    token_file = Path(config.get("token_file", "~/.hermes/gitea_token")).expanduser()
    if token_file.exists():
        return token_file.read_text().strip()

    return None


# ---------------------------------------------------------------------------
# Daily Run Integration
# ---------------------------------------------------------------------------


async def check_daily_run_quests(agent_id: str = "system") -> list[dict]:
    """Check and award Daily Run related quests.

    Called by the Daily Run system when metrics are updated.

    Returns:
        List of rewards awarded
    """
    # Check if auto-detect is enabled
    _, quest_settings = load_quest_config()
    if not quest_settings.get("auto_detect_on_daily_run", True):
        return []

    # Build context from Daily Run metrics
    metrics = await _fetch_daily_run_metrics()
    context = {
        "sessions_completed": metrics.get("sessions_completed", 0),
        "sessions_previous": metrics.get("sessions_previous", 0),
    }

    # Add closed issues for issue_count quests
    active_quests = get_active_quests()
    for quest in active_quests:
        if quest.quest_type.value == "issue_count":
            labels = quest.criteria.get("issue_labels", [])
            context["closed_issues"] = await _fetch_closed_issues(labels)
            break  # Only need to fetch once

    # Evaluate all quests
    rewards = auto_evaluate_all_quests(agent_id, context)

    return rewards
