"""CLI commands for observability and repair."""
from __future__ import annotations

import json
from datetime import datetime
from typing import Any

import click

from proxym.cli._client import make_client, print_json


_OBS_BASE_KEYS = {"timestamp", "level", "source", "event", "traceback"}


def _short_value(value: Any, limit: int = 240) -> str:
    """Render a value on one line and truncate it for shell output."""
    if value is None:
        return ""
    if isinstance(value, (dict, list, tuple)):
        try:
            text = json.dumps(value, ensure_ascii=False, default=str)
        except TypeError:
            text = str(value)
    else:
        text = str(value)
    text = text.replace("\r", "").replace("\n", " ⏎ ")
    if len(text) > limit:
        return text[: limit - 1] + "…"
    return text


def _format_entry(entry: dict[str, Any], *, include_traceback: bool = True) -> str:
    """Format a structured observability entry for CLI display."""
    ts = entry.get("timestamp", "")
    if isinstance(ts, (int, float)):
        ts_str = datetime.fromtimestamp(float(ts)).strftime("%Y-%m-%d %H:%M:%S")
    else:
        ts_str = _short_value(ts, 32) if ts else "?"

    level = str(entry.get("level", "?")).upper()
    source = _short_value(entry.get("source", "?"), 80)
    event = _short_value(entry.get("event", ""), 60)

    parts = [f"{ts_str} {level:7s} {source} {event}".rstrip()]

    preferred_keys = (
        "error_type",
        "duration_ms",
        "slow",
        "method",
        "path",
        "status",
        "job_id",
        "ticket_id",
        "tool",
        "message",
        "error",
        "kwargs",
        "result",
    )
    handled = set(_OBS_BASE_KEYS)
    for key in preferred_keys:
        handled.add(key)
        value = entry.get(key)
        if value in (None, "", [], {}):
            continue
        parts.append(f"{key}={_short_value(value, 220)}")

    for key, value in entry.items():
        if key in handled or value in (None, "", [], {}):
            continue
        parts.append(f"{key}={_short_value(value, 220)}")

    line = "  " + " | ".join(parts)
    if include_traceback and entry.get("traceback"):
        line += f"\n    traceback: {_short_value(entry['traceback'], 360)}"
    return line


def cmd_obs_errors(args):
    client = make_client(args.proxy, args.key)
    r = client.get("/observability/errors")
    r.raise_for_status()
    data = r.json()
    click.echo(f"  Errors: {data['total_errors']}/{data['total_logs']} logs")
    for src, count in data.get("by_source", {}).items():
        click.echo(f"    {src}: {count}")
    recent_errors = data.get("recent_errors") or []
    if recent_errors:
        click.echo("  Recent errors:")
        for entry in recent_errors[-5:]:
            click.echo(_format_entry(entry))


def cmd_obs_health(args):
    client = make_client(args.proxy, args.key)
    r = client.get("/observability/health-summary")
    r.raise_for_status()
    data = r.json()
    click.echo(f"  Active issues: {data['active_issues']} ({data['critical']} critical)")
    for evt in data.get("recent", []):
        icon = {"critical": "\u274c", "warning": "\u26a0\ufe0f", "resolved": "\u2705"}.get(evt["severity"], "\u2b55")
        click.echo(f"  {icon} [{evt['source']}] {evt['title']}")


def cmd_obs_repair(args):
    import httpx
    if getattr(args, "from_logs", False):
        r = httpx.post(
            f"{args.proxy}/observability/repair-from-logs",
            headers={"Authorization": f"Bearer {args.key}"},
            timeout=60,
        )
    else:
        error_text = getattr(args, "error", "") or ""
        mode = getattr(args, "mode", "suggest") or "suggest"
        r = httpx.post(
            f"{args.proxy}/observability/repair",
            json={"error_text": error_text, "mode": mode},
            headers={"Authorization": f"Bearer {args.key}"},
            timeout=60,
        )
    r.raise_for_status()
    data = r.json()
    if "error" in data:
        click.echo(f"  Error: {data['error']}")
        return
    click.echo(f"  Diagnosis: {data.get('diagnosis', '?')}")
    click.echo(f"  Suggestion: {data.get('suggestion', '?')}")
    if data.get("applied"):
        click.echo(f"  Fix applied — tests: {data.get('test_result', '?')}")
    elif data.get("diff"):
        click.echo(f"  Diff available ({len(data['diff'])} chars) — use --mode apply to auto-apply")


def cmd_obs_logs(args):
    client = make_client(args.proxy, args.key)
    params = {"limit": getattr(args, "limit", 50)}
    level = getattr(args, "level", None)
    if level:
        params["level"] = level
    r = client.get("/observability/logs", params=params)
    r.raise_for_status()
    data = r.json()
    for entry in data:
        click.echo(_format_entry(entry))
