"""quark diff — compare two cognitive fossils."""
from __future__ import annotations

import json
import typer
from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from rich.columns import Columns
from rich import box

from quark import client

console = Console()

_DRIFT_THRESHOLD = 0.05   # delta stability considered significant


def _parse_list(val) -> list:
    if isinstance(val, list):
        return val
    if isinstance(val, str):
        try:
            return json.loads(val)
        except Exception:
            return [val] if val else []
    return []


def run(
    id_a: str = typer.Argument(..., metavar="FOSSIL_A", help="ID or prefix of fossil A"),
    id_b: str = typer.Argument(..., metavar="FOSSIL_B", help="ID or prefix of fossil B"),
    output_json: bool = typer.Option(False, "--json"),
):
    """
    Compare two cognitive fossils — behavioral drift, stability delta, diverging invariants.

    Examples:

      quark diff abc123 def456

      quark diff v1.1 v1.3          # if fossil names are used as IDs
    """
    with console.status("[cyan]Fetching fossils…[/cyan]"):
        try:
            fa = client.get_fossil(id_a)
            fb = client.get_fossil(id_b)
        except client.QuarkError as e:
            console.print(f"[bold red]✗[/bold red] {e.detail}")
            raise typer.Exit(1)

    sa = fa.get("stability_score") or 0.0
    sb = fb.get("stability_score") or 0.0
    delta = sb - sa

    inv_a = set(
        i.get("description", i) if isinstance(i, dict) else str(i)
        for i in _parse_list(fa.get("behavioral_invariants"))
    )
    inv_b = set(
        i.get("description", i) if isinstance(i, dict) else str(i)
        for i in _parse_list(fb.get("behavioral_invariants"))
    )
    gained  = inv_b - inv_a
    lost    = inv_a - inv_b
    shared  = inv_a & inv_b

    sig_a = (fa.get("cognitive_signature") or "")[:60]
    sig_b = (fb.get("cognitive_signature") or "")[:60]
    sig_changed = sig_a != sig_b

    if output_json:
        console.print_json(json.dumps({
            "fossil_a": {"id": fa["id"], "name": fa.get("name"), "stability": sa},
            "fossil_b": {"id": fb["id"], "name": fb.get("name"), "stability": sb},
            "stability_delta": round(delta, 4),
            "drift_detected": abs(delta) > _DRIFT_THRESHOLD,
            "signature_changed": sig_changed,
            "invariants": {
                "shared": len(shared),
                "gained": list(gained),
                "lost":   list(lost),
            },
        }))
        return

    drift_flag = abs(delta) > _DRIFT_THRESHOLD
    drift_color = "red" if delta < -_DRIFT_THRESHOLD else "green" if delta > _DRIFT_THRESHOLD else "yellow"
    delta_str = f"{'+' if delta >= 0 else ''}{delta:.3f}"

    console.print()
    console.print(
        Panel.fit(
            "[bold cyan]◈  Cognitive diff[/bold cyan]  "
            f"[dim]{fa.get('name','A')}[/dim] → [dim]{fb.get('name','B')}[/dim]",
            border_style="cyan",
        )
    )

    # Stability table
    t = Table(box=box.SIMPLE, show_header=True, header_style="bold dim")
    t.add_column("Fossil",     width=28)
    t.add_column("ID",         width=10, style="dim")
    t.add_column("Stability σ", justify="right")
    t.add_row(fa.get("name","A"), fa["id"][:8]+"…", f"{sa:.3f}")
    t.add_row(fb.get("name","B"), fb["id"][:8]+"…", f"{sb:.3f}")
    t.add_row("", "Δ", f"[{drift_color}]{delta_str}[/{drift_color}]")
    console.print(t)

    if drift_flag:
        label = "DRIFT DETECTED" if delta < 0 else "STABILITY GAIN"
        console.print(
            f"  [{drift_color}]⚠  {label}[/{drift_color}]  "
            f"[dim]Δ = {delta_str} (threshold ±{_DRIFT_THRESHOLD})[/dim]"
        )
    else:
        console.print("  [green]✓  Stable[/green]  [dim]Δ within threshold[/dim]")

    # Cognitive signature
    if sig_changed:
        console.print()
        console.print("  [bold]Cognitive signature changed[/bold]")
        console.print(f"  [red]−[/red] [dim]{sig_a}…[/dim]")
        console.print(f"  [green]+[/green] [dim]{sig_b}…[/dim]")

    # Invariants
    if gained or lost:
        console.print()
        console.print(
            f"  [bold]Behavioral invariants[/bold]  "
            f"[dim]{len(shared)} shared · "
            f"[green]+{len(gained)}[/green] · "
            f"[red]-{len(lost)}[/red][/dim]"
        )
        for i in list(gained)[:4]:
            console.print(f"  [green]+[/green] {i}")
        for i in list(lost)[:4]:
            console.print(f"  [red]−[/red] {i}")
        extra = (len(gained) - 4) + (len(lost) - 4)
        if extra > 0:
            console.print(f"  [dim]  … +{extra} more[/dim]")
    else:
        console.print()
        console.print("  [dim]Behavioral invariants unchanged[/dim]")

    console.print()
