"""Agent scorecard routes — API endpoints for generating and viewing scorecards."""

from __future__ import annotations

import logging
from datetime import datetime

from fastapi import APIRouter, Query, Request
from fastapi.responses import HTMLResponse, JSONResponse

from dashboard.services.scorecard_service import (
    PeriodType,
    ScorecardSummary,
    generate_all_scorecards,
    generate_scorecard,
    get_tracked_agents,
)
from dashboard.templating import templates

logger = logging.getLogger(__name__)

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


def _format_period_label(period_type: PeriodType) -> str:
    """Format a period type for display."""
    return "Daily" if period_type == PeriodType.daily else "Weekly"


def _parse_period(period: str) -> PeriodType:
    """Parse period string into PeriodType, defaulting to daily on invalid input.

    Args:
        period: The period string ('daily' or 'weekly')

    Returns:
        PeriodType.daily or PeriodType.weekly
    """
    try:
        return PeriodType(period.lower())
    except ValueError:
        return PeriodType.daily


def _format_token_display(token_net: int) -> str:
    """Format token net value with +/- prefix for display.

    Args:
        token_net: The net token value

    Returns:
        Formatted string with + prefix for positive values
    """
    return f"{'+' if token_net > 0 else ''}{token_net}"


def _format_token_class(token_net: int) -> str:
    """Get CSS class for token net value based on sign.

    Args:
        token_net: The net token value

    Returns:
        'text-success' for positive/zero, 'text-danger' for negative
    """
    return "text-success" if token_net >= 0 else "text-danger"


def _build_patterns_html(patterns: list[str]) -> str:
    """Build HTML for patterns section if patterns exist.

    Args:
        patterns: List of pattern strings

    Returns:
        HTML string for patterns section or empty string
    """
    if not patterns:
        return ""

    patterns_list = "".join([f"<li>{p}</li>" for p in patterns])
    return f"""
    <div class="mt-3">
        <h6>Patterns</h6>
        <ul class="list-unstyled text-info">
            {patterns_list}
        </ul>
    </div>
    """


def _build_narrative_html(bullets: list[str]) -> str:
    """Build HTML for narrative bullets.

    Args:
        bullets: List of narrative bullet strings

    Returns:
        HTML string with list items
    """
    return "".join([f"<li>{b}</li>" for b in bullets])


def _build_metrics_row_html(metrics: dict) -> str:
    """Build HTML for the metrics summary row.

    Args:
        metrics: Dictionary with PRs, issues, tests, and token metrics

    Returns:
        HTML string for the metrics row
    """
    prs_opened = metrics["prs_opened"]
    prs_merged = metrics["prs_merged"]
    pr_merge_rate = int(metrics["pr_merge_rate"] * 100)
    issues_touched = metrics["issues_touched"]
    tests_affected = metrics["tests_affected"]
    token_net = metrics["token_net"]

    token_class = _format_token_class(token_net)
    token_display = _format_token_display(token_net)

    return f"""
    <div class="row text-center small">
        <div class="col">
            <div class="text-muted">PRs</div>
            <div class="fw-bold">{prs_opened}/{prs_merged}</div>
            <div class="text-muted" style="font-size: 0.75rem;">
                {pr_merge_rate}% merged
            </div>
        </div>
        <div class="col">
            <div class="text-muted">Issues</div>
            <div class="fw-bold">{issues_touched}</div>
        </div>
        <div class="col">
            <div class="text-muted">Tests</div>
            <div class="fw-bold">{tests_affected}</div>
        </div>
        <div class="col">
            <div class="text-muted">Tokens</div>
            <div class="fw-bold {token_class}">{token_display}</div>
        </div>
    </div>
    """


def _render_scorecard_panel(
    agent_id: str,
    period_type: PeriodType,
    data: dict,
) -> str:
    """Render HTML for a single scorecard panel.

    Args:
        agent_id: The agent ID
        period_type: Daily or weekly period
        data: Scorecard data dictionary with metrics, patterns, narrative_bullets

    Returns:
        HTML string for the scorecard panel
    """
    patterns_html = _build_patterns_html(data.get("patterns", []))
    bullets_html = _build_narrative_html(data.get("narrative_bullets", []))
    metrics_row = _build_metrics_row_html(data["metrics"])

    return f"""
    <div class="card mc-panel">
        <div class="card-header d-flex justify-content-between align-items-center">
            <h5 class="card-title mb-0">{agent_id.title()}</h5>
            <span class="badge bg-secondary">{_format_period_label(period_type)}</span>
        </div>
        <div class="card-body">
            <ul class="list-unstyled mb-3">
                {bullets_html}
            </ul>
            {metrics_row}
            {patterns_html}
        </div>
    </div>
    """


def _render_empty_scorecard(agent_id: str) -> str:
    """Render HTML for an empty scorecard (no activity).

    Args:
        agent_id: The agent ID

    Returns:
        HTML string for the empty scorecard panel
    """
    return f"""
    <div class="card mc-panel">
        <h5 class="card-title">{agent_id.title()}</h5>
        <p class="text-muted">No activity recorded for this period.</p>
    </div>
    """


def _render_error_scorecard(agent_id: str, error: str) -> str:
    """Render HTML for a scorecard that failed to load.

    Args:
        agent_id: The agent ID
        error: Error message string

    Returns:
        HTML string for the error scorecard panel
    """
    return f"""
    <div class="card mc-panel border-danger">
        <h5 class="card-title">{agent_id.title()}</h5>
        <p class="text-danger">Error loading scorecard: {error}</p>
    </div>
    """


def _render_single_panel_wrapper(
    agent_id: str,
    period_type: PeriodType,
    scorecard: ScorecardSummary | None,
) -> str:
    """Render a complete scorecard panel with wrapper div for single panel view.

    Args:
        agent_id: The agent ID
        period_type: Daily or weekly period
        scorecard: ScorecardSummary object or None

    Returns:
        HTML string for the complete panel
    """
    if scorecard is None:
        return _render_empty_scorecard(agent_id)

    return _render_scorecard_panel(agent_id, period_type, scorecard.to_dict())


@router.get("/api/agents")
async def list_tracked_agents() -> dict[str, list[str]]:
    """Return the list of tracked agent IDs.

    Returns:
        Dict with "agents" key containing list of agent IDs
    """
    return {"agents": get_tracked_agents()}


@router.get("/api/{agent_id}")
async def get_agent_scorecard(
    agent_id: str,
    period: str = Query(default="daily", description="Period type: 'daily' or 'weekly'"),
) -> JSONResponse:
    """Generate a scorecard for a specific agent.

    Args:
        agent_id: The agent ID (e.g., 'kimi', 'claude')
        period: 'daily' or 'weekly' (default: daily)

    Returns:
        JSON response with scorecard data
    """
    try:
        period_type = PeriodType(period.lower())
    except ValueError:
        return JSONResponse(
            status_code=400,
            content={"error": f"Invalid period '{period}'. Use 'daily' or 'weekly'."},
        )

    try:
        scorecard = generate_scorecard(agent_id, period_type)

        if scorecard is None:
            return JSONResponse(
                status_code=404,
                content={"error": f"No scorecard found for agent '{agent_id}'"},
            )

        return JSONResponse(content=scorecard.to_dict())

    except Exception as exc:
        logger.error("Failed to generate scorecard for %s: %s", agent_id, exc)
        return JSONResponse(
            status_code=500,
            content={"error": f"Failed to generate scorecard: {str(exc)}"},
        )


@router.get("/api")
async def get_all_scorecards(
    period: str = Query(default="daily", description="Period type: 'daily' or 'weekly'"),
) -> JSONResponse:
    """Generate scorecards for all tracked agents.

    Args:
        period: 'daily' or 'weekly' (default: daily)

    Returns:
        JSON response with list of scorecard data
    """
    try:
        period_type = PeriodType(period.lower())
    except ValueError:
        return JSONResponse(
            status_code=400,
            content={"error": f"Invalid period '{period}'. Use 'daily' or 'weekly'."},
        )

    try:
        scorecards = generate_all_scorecards(period_type)
        return JSONResponse(
            content={
                "period": period_type.value,
                "scorecards": [s.to_dict() for s in scorecards],
                "count": len(scorecards),
            }
        )

    except Exception as exc:
        logger.error("Failed to generate scorecards: %s", exc)
        return JSONResponse(
            status_code=500,
            content={"error": f"Failed to generate scorecards: {str(exc)}"},
        )


@router.get("", response_class=HTMLResponse)
async def scorecards_page(request: Request) -> HTMLResponse:
    """Render the scorecards dashboard page.

    Returns:
        HTML page with scorecard interface
    """
    agents = get_tracked_agents()
    return templates.TemplateResponse(
        request,
        "scorecards.html",
        {
            "agents": agents,
            "periods": ["daily", "weekly"],
        },
    )


@router.get("/panel/{agent_id}", response_class=HTMLResponse)
async def agent_scorecard_panel(
    request: Request,
    agent_id: str,
    period: str = Query(default="daily"),
) -> HTMLResponse:
    """Render an individual agent scorecard panel (for HTMX).

    Args:
        request: The request object
        agent_id: The agent ID
        period: 'daily' or 'weekly'

    Returns:
        HTML panel with scorecard content
    """
    period_type = _parse_period(period)

    try:
        scorecard = generate_scorecard(agent_id, period_type)
        html_content = _render_single_panel_wrapper(agent_id, period_type, scorecard)
        return HTMLResponse(content=html_content)

    except Exception as exc:
        logger.error("Failed to render scorecard panel for %s: %s", agent_id, exc)
        return HTMLResponse(content=_render_error_scorecard(agent_id, str(exc)))


def _render_all_panels_grid(
    scorecards: list[ScorecardSummary],
    period_type: PeriodType,
) -> str:
    """Render all scorecard panels in a grid layout.

    Args:
        scorecards: List of scorecard summaries
        period_type: Daily or weekly period

    Returns:
        HTML string with all panels in a grid
    """
    panels: list[str] = []
    for scorecard in scorecards:
        panel_html = _render_scorecard_panel(
            scorecard.agent_id,
            period_type,
            scorecard.to_dict(),
        )
        # Wrap each panel in a grid column
        wrapped = f'<div class="col-md-6 col-lg-4 mb-3">{panel_html}</div>'
        panels.append(wrapped)

    return f"""
    <div class="row">
        {"".join(panels)}
    </div>
    <div class="text-muted small mt-2">
        Generated: {datetime.now().strftime("%Y-%m-%d %H:%M:%S UTC")}
    </div>
    """


@router.get("/all/panels", response_class=HTMLResponse)
async def all_scorecard_panels(
    request: Request,
    period: str = Query(default="daily"),
) -> HTMLResponse:
    """Render all agent scorecard panels (for HTMX).

    Args:
        request: The request object
        period: 'daily' or 'weekly'

    Returns:
        HTML with all scorecard panels
    """
    period_type = _parse_period(period)

    try:
        scorecards = generate_all_scorecards(period_type)
        html_content = _render_all_panels_grid(scorecards, period_type)
        return HTMLResponse(content=html_content)

    except Exception as exc:
        logger.error("Failed to render all scorecard panels: %s", exc)
        return HTMLResponse(
            content=f'<div class="alert alert-danger">Error loading scorecards: {exc}</div>'
        )
