"""Suite-aware 3-step dashboard pipeline orchestrator.

Step 1: MCP CLI auth check / auto-refresh
Step 2: Generate the dashboard HTML + failures JSON
Step 3: AI analysis via code-puppy (optional)
"""
import json
import subprocess
import sys
from datetime import datetime
from pathlib import Path


# ---------------------------------------------------------------------------
# Step 1 — MCP CLI auth check
# ---------------------------------------------------------------------------

_MCP_CLI = Path.home() / ".mcp-cli" / "bin" / "mcp-cli"
_TOKENS_FILE = Path.home() / ".mcp-cli" / "tokens.json"


def _token_expires_in_minutes() -> float | None:
    if not _TOKENS_FILE.exists():
        return None
    try:
        data = json.loads(_TOKENS_FILE.read_text())
        expires_at = data.get("expires_at")
        if not expires_at:
            return None
        exp_dt = datetime.fromisoformat(expires_at)
        delta = exp_dt - datetime.now(exp_dt.tzinfo)
        return delta.total_seconds() / 60
    except Exception:  # noqa: BLE001
        return None


def step_auth_refresh() -> bool:
    """Ensure the MCP CLI token is valid, auto-refreshing if needed."""
    print("\nStep 1/3 — MCP CLI auth check", flush=True)

    if not _MCP_CLI.exists():
        print(f"  Warning: mcp-cli not found at {_MCP_CLI}. Skipping token refresh.", flush=True)
        return True

    minutes = _token_expires_in_minutes()
    if minutes is not None and minutes > 30:
        print(f"  Token valid ({minutes:.0f} min remaining). No refresh needed.", flush=True)
        return True

    if minutes is not None and minutes > 0:
        print(f"  Token expires in {minutes:.0f} min — triggering refresh...", flush=True)
    else:
        print("  Token expired or unknown — attempting auto-refresh...", flush=True)

    result = subprocess.run(
        [str(_MCP_CLI), "auth", "status"],
        capture_output=True, text=True, timeout=30,
    )
    output = (result.stdout + result.stderr).strip()

    if result.returncode == 0 and "Authenticated" in output:
        print("  Token refreshed successfully.", flush=True)
        return True

    print("  Auth refresh failed. Run: mcp-cli auth login", flush=True)
    return False


# ---------------------------------------------------------------------------
# Step 2 — Dashboard generation
# ---------------------------------------------------------------------------

def step_generate_dashboard(
    suite: str,
    config: str,
    output: str,
    save_failures: str,
    scm_url: str | None,
    no_details: bool,
    auto_open: bool,
    days: int,
) -> bool:
    """Call the appropriate generator's run() function.

    Returns True on success.
    """
    label_map = {
        "karate":              "Karate",
        "playwright":          "Playwright",
        "playwright-monocart": "Monocart",
    }
    label = label_map.get(suite, suite)
    print(f"\nStep 2/3 — Generating {label} dashboard (last {days} days)", flush=True)

    Path(output).parent.mkdir(parents=True, exist_ok=True)

    if suite == "karate":
        from .karate_generator import run
    elif suite == "playwright":
        from .playwright_generator import run
    elif suite == "playwright-monocart":
        from .monocart_generator import run
    else:
        print(f"  Unknown suite: {suite}", flush=True)
        return False

    ok = run(
        config=config,
        output=output,
        scm_url=scm_url,
        days=days,
        no_details=no_details,
        save_failures=save_failures,
        auto_open=auto_open,
    )

    if ok:
        failures_path = Path(save_failures)
        if failures_path.exists():
            failures = json.loads(failures_path.read_text())
            print(f"  {len(failures)} failed flow(s) saved to {save_failures}", flush=True)
        else:
            print("  No failures file produced (all flows may have passed).", flush=True)

    return ok


# ---------------------------------------------------------------------------
# Step 3 — AI analysis
# ---------------------------------------------------------------------------

def step_ai_analysis(
    suite: str,
    config: str,
    output: str,
    save_failures: str,
    analysis_json: str,
    scm_url: str | None,
) -> bool:
    """Run AI analysis and regenerate dashboard with AI panel.

    For karate: uses a direct code-puppy --prompt call (prompt built inline).
    For playwright / playwright-monocart: uses ai_analyzer.analyze_failures().

    Returns True on success (or when there are no failures to analyse).
    """
    print("\nStep 3/3 — AI analysis", flush=True)

    failures_path = Path(save_failures)
    if not failures_path.exists():
        print("  No failures file found — skipping AI analysis.", flush=True)
        return True

    failures = json.loads(failures_path.read_text())
    if not failures:
        print("  No failures to analyse — all flows passed!", flush=True)
        return True

    print(f"  Analysing {len(failures)} failed flow(s)...", flush=True)

    if suite == "karate":
        ok = _karate_ai_step(failures, analysis_json, failures_path)
    else:
        ok = _playwright_ai_step(failures, analysis_json)

    if not ok:
        return False

    analysis_path = Path(analysis_json)
    if not analysis_path.exists():
        print(f"  Analysis JSON not found at {analysis_json}.", flush=True)
        return False

    print(f"  AI analysis written to {analysis_json}", flush=True)

    # Regenerate dashboard with analysis baked in
    print("  Regenerating dashboard with AI analysis panel...", flush=True)

    if suite == "karate":
        from .karate_generator import run
    elif suite == "playwright":
        from .playwright_generator import run
    else:
        from .monocart_generator import run

    regen_ok = run(
        config=config,
        output=output,
        scm_url=scm_url,
        no_details=True,
        save_failures=save_failures,
        analysis_json=analysis_json,
    )

    if regen_ok:
        print(f"  Dashboard updated with AI analysis -> {output}", flush=True)
    return regen_ok


def _karate_ai_step(failures: list, analysis_json: str, failures_path: Path) -> bool:
    """Karate AI step: build a prompt and call code-puppy --prompt directly."""
    import shutil

    code_puppy = shutil.which("code-puppy") or str(Path.home() / ".code-puppy-venv/bin/code-puppy")
    if not Path(code_puppy).exists():
        print(f"  Warning: code-puppy not found at {code_puppy}. Skipping AI step.", flush=True)
        return False

    failures_snippet = json.dumps(failures[:3], indent=2)
    prompt = f"""Analyse the karate test failures below and write a JSON analysis file.

Failure summary (from {failures_path}):
{failures_snippet}{'...' if len(failures) > 3 else ''}

For every failed flow in {failures_path}, produce a JSON object with:
  - "flow"           : exact flow name from the summary
  - "classification" : one of service_regression | environment_issue | test_issue | flaky
  - "severity"       : one of high | medium | low
  - "summary"        : 1-2 sentences describing what went wrong
  - "recommendation" : concrete next step for the engineering team

Write the complete JSON array to:
  {analysis_json}

That is the only output needed — do NOT regenerate the dashboard.
"""

    result = subprocess.run(
        [code_puppy, "--prompt", prompt],
        text=True,
        timeout=300,
    )
    return result.returncode == 0


def _playwright_ai_step(failures: list, analysis_json: str) -> bool:
    """Playwright/Monocart AI step: use the shared ai_analyzer module."""
    from .ai_analyzer import analyze_failures

    analysis = analyze_failures(failures)
    if not analysis:
        return False

    Path(analysis_json).write_text(json.dumps(analysis, indent=2))
    return True


# ---------------------------------------------------------------------------
# Summary printer
# ---------------------------------------------------------------------------

def print_summary(results: dict[str, bool], output: str) -> None:
    icons = {True: "OK", False: "FAIL"}
    print("\n" + "=" * 50, flush=True)
    print("  Pipeline summary", flush=True)
    print("=" * 50, flush=True)
    for step, ok in results.items():
        print(f"  [{icons[ok]}]  {step}", flush=True)
    print("=" * 50, flush=True)
    overall = all(results.values())
    print(f"  {'All done!' if overall else 'Completed with errors.'}", flush=True)
    print(f"  Dashboard -> {output}", flush=True)
    print("=" * 50 + "\n", flush=True)
