"""Eval reporter — table, JSON, and HTML output for eval results."""

from __future__ import annotations

import json
from pathlib import Path

from hatchdx.agent.eval.models import EvalCaseResult, EvalRunResult


# ---------------------------------------------------------------------------
# Table output (Rich)
# ---------------------------------------------------------------------------


def report_table(
    run_result: EvalRunResult,
    *,
    comparison: dict | None = None,
    comparison_cases: list[dict] | None = None,
) -> str:
    """Format eval results as a Rich-compatible table string.

    Args:
        run_result: The eval run result.
        comparison: Previous run summary (from storage) for regression detection.
        comparison_cases: Previous run case results (from storage).

    Returns:
        Formatted string for console output.
    """
    lines: list[str] = []

    # Header
    lines.append("")
    status_icon = "PASS" if run_result.failed == 0 else "FAIL"
    lines.append(
        f"  Eval: {run_result.suite_name} [{status_icon}]"
    )
    lines.append(f"  Agent: {run_result.agent_name}")
    lines.append(f"  Model: {run_result.model} (temperature={run_result.temperature})")
    lines.append("")

    # Build previous case status map for comparison
    prev_status: dict[str, str] = {}
    if comparison_cases:
        for case in comparison_cases:
            prev_status[case["case_name"]] = case["status"]

    # Case results table
    lines.append("  Results:")
    lines.append("")
    lines.append(f"  {'Case':<40} {'Status':<10} {'Latency':<12} {'Cost':<10} {'Change':<10}")
    lines.append(f"  {'-'*40} {'-'*10} {'-'*12} {'-'*10} {'-'*10}")

    for case_result in run_result.case_results:
        status = "PASS" if case_result.passed else "FAIL"
        latency = f"{case_result.latency_ms:.0f}ms"
        cost = f"${case_result.cost_usd:.4f}"

        # Compute change indicator
        change = ""
        prev = prev_status.get(case_result.case_name)
        if prev is not None:
            if prev == "passed" and not case_result.passed:
                change = "REGR"
            elif prev == "failed" and case_result.passed:
                change = "FIXED"

        name = case_result.case_name[:40]
        lines.append(f"  {name:<40} {status:<10} {latency:<12} {cost:<10} {change:<10}")

    # Summary
    lines.append("")
    lines.append(
        f"  Total: {run_result.total_cases} cases, "
        f"{run_result.passed} passed, {run_result.failed} failed"
    )
    lines.append(
        f"  Cost: ${run_result.total_cost:.4f} | "
        f"Tokens: {run_result.total_tokens:,}"
    )

    # Comparison summary
    if comparison:
        prev_cost = comparison.get("total_cost_usd", 0)
        prev_tokens = comparison.get("total_tokens", 0)
        curr_cost = run_result.total_cost
        curr_tokens = run_result.total_tokens

        if prev_cost > 0:
            cost_delta = ((curr_cost - prev_cost) / prev_cost) * 100
            cost_sign = "+" if cost_delta > 0 else ""
            lines.append(
                f"  Cost delta: ${prev_cost:.4f} -> ${curr_cost:.4f} ({cost_sign}{cost_delta:.0f}%)"
            )
        if prev_tokens > 0:
            token_delta = ((curr_tokens - prev_tokens) / prev_tokens) * 100
            token_sign = "+" if token_delta > 0 else ""
            lines.append(
                f"  Token delta: {prev_tokens:,} -> {curr_tokens:,} ({token_sign}{token_delta:.0f}%)"
            )

    # Failed assertion details
    failed_cases = [c for c in run_result.case_results if not c.passed]
    if failed_cases:
        lines.append("")
        lines.append("  Failures:")
        for case_result in failed_cases:
            lines.append(f"    {case_result.case_name}:")
            if case_result.error_message:
                lines.append(f"      {case_result.error_message}")
            else:
                for ar in case_result.assertion_results:
                    if not ar.passed:
                        lines.append(f"      [{ar.assertion_type}] {ar.message}")

    lines.append("")
    return "\n".join(lines)


# ---------------------------------------------------------------------------
# Multi-run aggregation
# ---------------------------------------------------------------------------


def report_multi_run_table(run_results: list[EvalRunResult]) -> str:
    """Format aggregated results from multiple runs.

    Shows per-case pass rate across runs.
    """
    if not run_results:
        return "  No results to display.\n"

    lines: list[str] = []

    # Gather case names from first run (all runs have same cases)
    case_names = [c.case_name for c in run_results[0].case_results]
    num_runs = len(run_results)

    lines.append("")
    lines.append(f"  Eval: {run_results[0].suite_name} ({num_runs} runs)")
    lines.append(f"  Agent: {run_results[0].agent_name}")
    lines.append(f"  Model: {run_results[0].model}")
    lines.append("")

    lines.append(f"  {'Case':<40} {'Pass Rate':<12} {'Avg Cost':<10} {'Avg Latency':<12}")
    lines.append(f"  {'-'*40} {'-'*12} {'-'*10} {'-'*12}")

    for case_name in case_names:
        # Find this case in each run
        pass_count = 0
        total_cost = 0.0
        total_latency = 0.0

        for run_result in run_results:
            for case_result in run_result.case_results:
                if case_result.case_name == case_name:
                    if case_result.passed:
                        pass_count += 1
                    total_cost += case_result.cost_usd
                    total_latency += case_result.latency_ms
                    break

        rate = f"{pass_count}/{num_runs}"
        avg_cost = f"${total_cost / num_runs:.4f}"
        avg_latency = f"{total_latency / num_runs:.0f}ms"
        name = case_name[:40]
        lines.append(f"  {name:<40} {rate:<12} {avg_cost:<10} {avg_latency:<12}")

    # Overall aggregation
    total_passed = sum(r.passed for r in run_results)
    total_cases = sum(r.total_cases for r in run_results)
    total_cost = sum(r.total_cost for r in run_results)

    lines.append("")
    lines.append(f"  Overall: {total_passed}/{total_cases} cases passed across {num_runs} runs")
    lines.append(f"  Total cost: ${total_cost:.4f}")
    lines.append("")

    return "\n".join(lines)


# ---------------------------------------------------------------------------
# JSON output
# ---------------------------------------------------------------------------


def report_json(run_result: EvalRunResult) -> str:
    """Format eval results as JSON."""
    data = {
        "suite": run_result.suite_name,
        "agent": run_result.agent_name,
        "model": run_result.model,
        "temperature": run_result.temperature,
        "started_at": run_result.started_at.isoformat(),
        "completed_at": run_result.completed_at.isoformat() if run_result.completed_at else None,
        "summary": {
            "total": run_result.total_cases,
            "passed": run_result.passed,
            "failed": run_result.failed,
            "cost_usd": round(run_result.total_cost, 6),
            "tokens": run_result.total_tokens,
        },
        "cases": [
            {
                "name": c.case_name,
                "input": c.input,
                "output": c.output,
                "passed": c.passed,
                "latency_ms": round(c.latency_ms, 1),
                "tokens": c.tokens_used,
                "cost_usd": round(c.cost_usd, 6),
                "error": c.error_message,
                "assertions": [
                    {
                        "type": ar.assertion_type,
                        "passed": ar.passed,
                        "message": ar.message,
                    }
                    for ar in c.assertion_results
                ],
                "tool_calls": c.tool_calls_json,
            }
            for c in run_result.case_results
        ],
    }
    return json.dumps(data, indent=2)


def report_multi_run_json(run_results: list[EvalRunResult]) -> str:
    """Format aggregated results from multiple runs as JSON."""
    return json.dumps(
        {"runs": [json.loads(report_json(r)) for r in run_results]},
        indent=2,
    )


# ---------------------------------------------------------------------------
# HTML report
# ---------------------------------------------------------------------------


def report_cross_model_table(run_results: list[EvalRunResult]) -> str:
    """Format side-by-side comparison of eval results across models.

    Shows per-model summary and per-case comparison.
    """
    if not run_results:
        return "  No results to display.\n"

    lines: list[str] = []

    lines.append("")
    lines.append(f"  Cross-Model Eval: {run_results[0].suite_name}")
    lines.append(f"  Agent: {run_results[0].agent_name}")
    lines.append("")

    # Model summary row
    model_names = [r.model for r in run_results]
    header_parts = [f"{'Case':<35}"]
    for model in model_names:
        # Truncate model name to fit
        display = model[:20] if len(model) > 20 else model
        header_parts.append(f"{display:<22}")
    lines.append("  " + " ".join(header_parts))

    divider_parts = [f"{'-'*35}"]
    for _ in model_names:
        divider_parts.append(f"{'-'*22}")
    lines.append("  " + " ".join(divider_parts))

    # Gather all case names from the first run
    if run_results[0].case_results:
        case_names = [c.case_name for c in run_results[0].case_results]
    else:
        case_names = []

    for case_name in case_names:
        row_parts = [f"{case_name[:35]:<35}"]
        for run_result in run_results:
            case_result = None
            for c in run_result.case_results:
                if c.case_name == case_name:
                    case_result = c
                    break

            if case_result is None:
                row_parts.append(f"{'--':<22}")
            else:
                status = "PASS" if case_result.passed else "FAIL"
                cell = f"{status} ${case_result.cost_usd:.4f}"
                row_parts.append(f"{cell:<22}")

        lines.append("  " + " ".join(row_parts))

    # Summary per model
    lines.append("")
    lines.append("  Summary:")
    lines.append("")
    lines.append(f"  {'Model':<25} {'Passed':<10} {'Failed':<10} {'Cost':<12} {'Tokens':<12}")
    lines.append(f"  {'-'*25} {'-'*10} {'-'*10} {'-'*12} {'-'*12}")

    for run_result in run_results:
        model = run_result.model[:25]
        passed = str(run_result.passed)
        failed = str(run_result.failed)
        cost = f"${run_result.total_cost:.4f}"
        tokens = f"{run_result.total_tokens:,}"
        lines.append(f"  {model:<25} {passed:<10} {failed:<10} {cost:<12} {tokens:<12}")

    lines.append("")
    return "\n".join(lines)


def report_cross_model_json(run_results: list[EvalRunResult]) -> str:
    """Format cross-model comparison as JSON."""
    models = []
    for r in run_results:
        models.append({
            "model": r.model,
            "summary": {
                "total": r.total_cases,
                "passed": r.passed,
                "failed": r.failed,
                "cost_usd": round(r.total_cost, 6),
                "tokens": r.total_tokens,
            },
            "cases": [
                {
                    "name": c.case_name,
                    "passed": c.passed,
                    "latency_ms": round(c.latency_ms, 1),
                    "cost_usd": round(c.cost_usd, 6),
                    "tokens": c.tokens_used,
                }
                for c in r.case_results
            ],
        })

    return json.dumps({"cross_model": models}, indent=2)


def report_html(run_result: EvalRunResult) -> str:
    """Generate an HTML report for sharing."""
    cases_html = ""
    for c in run_result.case_results:
        status_class = "pass" if c.passed else "fail"
        status_text = "PASS" if c.passed else "FAIL"

        assertions_html = ""
        for ar in c.assertion_results:
            ar_class = "pass" if ar.passed else "fail"
            ar_icon = "&#10003;" if ar.passed else "&#10007;"
            assertions_html += (
                f'<div class="assertion {ar_class}">'
                f"{ar_icon} [{ar.assertion_type}] {ar.message}</div>\n"
            )

        cases_html += f"""
        <div class="case {status_class}">
            <div class="case-header">
                <span class="case-name">{c.case_name}</span>
                <span class="case-status {status_class}">{status_text}</span>
                <span class="case-stats">
                    {c.latency_ms:.0f}ms | {c.tokens_used:,} tokens | ${c.cost_usd:.4f}
                </span>
            </div>
            <div class="case-input">Input: {c.input}</div>
            <div class="assertions">{assertions_html}</div>
        </div>
"""

    return f"""<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Eval Report: {run_result.suite_name}</title>
    <style>
        body {{ font-family: -apple-system, BlinkMacSystemFont, sans-serif; max-width: 900px; margin: 40px auto; padding: 0 20px; background: #0d1117; color: #c9d1d9; }}
        h1 {{ color: #f0f6fc; border-bottom: 1px solid #30363d; padding-bottom: 12px; }}
        .summary {{ background: #161b22; padding: 16px; border-radius: 6px; margin-bottom: 24px; }}
        .summary span {{ margin-right: 24px; }}
        .case {{ background: #161b22; border-radius: 6px; margin-bottom: 12px; padding: 16px; border-left: 3px solid #30363d; }}
        .case.pass {{ border-left-color: #3fb950; }}
        .case.fail {{ border-left-color: #f85149; }}
        .case-header {{ display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }}
        .case-name {{ font-weight: 600; }}
        .case-status {{ font-size: 12px; font-weight: 600; padding: 2px 8px; border-radius: 12px; }}
        .case-status.pass {{ background: #238636; color: #fff; }}
        .case-status.fail {{ background: #da3633; color: #fff; }}
        .case-stats {{ color: #8b949e; font-size: 13px; margin-left: auto; }}
        .case-input {{ color: #8b949e; font-size: 13px; margin-bottom: 8px; }}
        .assertion {{ font-size: 13px; padding: 2px 0; }}
        .assertion.pass {{ color: #3fb950; }}
        .assertion.fail {{ color: #f85149; }}
    </style>
</head>
<body>
    <h1>Eval Report: {run_result.suite_name}</h1>
    <div class="summary">
        <span>Agent: {run_result.agent_name}</span>
        <span>Model: {run_result.model}</span>
        <span>Cases: {run_result.passed}/{run_result.total_cases} passed</span>
        <span>Cost: ${run_result.total_cost:.4f}</span>
        <span>Tokens: {run_result.total_tokens:,}</span>
    </div>
    {cases_html}
</body>
</html>"""
