"""
CrashSense TUI — Rich-based interactive terminal interface.

Provides a menu-driven experience for diagnosing blockchain transactions,
switching chains/providers, and viewing diagnosis history.
"""

from __future__ import annotations

from rich.console import Console
from rich.panel import Panel
from rich.prompt import Prompt
from rich.table import Table

from crashsense import __version__, __app_name__
from crashsense.config import (
    load_config,
    save_config,
    get_api_key,
    SUPPORTED_CHAINS,
)
from crashsense.utils import is_valid_tx_hash, normalise_tx_hash

console = Console()

MENU = """
[bold cyan]1)[/bold cyan] Diagnose transaction by hash
[bold cyan]2)[/bold cyan] Diagnose raw error text
[bold cyan]3)[/bold cyan] Switch chain
[bold cyan]4)[/bold cyan] Switch LLM provider
[bold cyan]5)[/bold cyan] View diagnosis history
[bold cyan]6)[/bold cyan] Configuration
[bold cyan]7)[/bold cyan] Quit
"""


def run_tui():
    """Entry-point for the interactive TUI."""
    console.clear()
    console.print(Panel(
        f"[bold cyan]{__app_name__}[/bold cyan] v{__version__}\n"
        "[dim]AI Agent for DeFi Transaction Failure Diagnosis[/dim]",
        title=f"{__app_name__} TUI",
        border_style="cyan",
    ))

    while True:
        console.print(MENU)
        choice = Prompt.ask("Choose an option", choices=["1", "2", "3", "4", "5", "6", "7"], default="1")

        if choice == "1":
            _tui_diagnose_tx()
        elif choice == "2":
            _tui_diagnose_raw()
        elif choice == "3":
            _tui_switch_chain()
        elif choice == "4":
            _tui_switch_provider()
        elif choice == "5":
            _tui_history()
        elif choice == "6":
            _tui_config()
        elif choice == "7":
            console.print("[cyan]Goodbye![/cyan]")
            break


# ── 1) Diagnose tx ────────────────────────────────────────────────────────

def _tui_diagnose_tx():
    tx_hash = Prompt.ask("[cyan]Transaction hash[/cyan]")
    if not is_valid_tx_hash(tx_hash):
        console.print("[red]Invalid hash. Expected 0x + 64 hex characters.[/red]")
        return

    tx_hash = normalise_tx_hash(tx_hash)
    cfg = load_config()

    from crashsense.core.tx_analyzer import TxAnalyzer
    from crashsense.core.remediation import RemediationEngine
    from crashsense.core.memory import MemoryStore

    analyzer = TxAnalyzer(
        provider=cfg.get("provider", "gemini"),
        chain=cfg.get("chain", {}).get("name", "ethereum"),
    )

    with console.status("[cyan]Fetching on-chain data & diagnosing…[/cyan]"):
        result = analyzer.diagnose(tx_hash)

    _render_result(result)

    # Save to memory
    try:
        mem = MemoryStore()
        analysis = result.get("analysis", {})
        ctx = result.get("tx_context", {})
        mem.save_diagnosis(
            tx_hash=tx_hash,
            chain=ctx.get("chain", cfg.get("chain", {}).get("name", "ethereum")),
            summary=analysis.get("explanation", ""),
            root_cause=analysis.get("root_cause", ""),
            suggested_fix=analysis.get("suggested_fix", ""),
            status=ctx.get("status", ""),
            function_called=ctx.get("function_called", ""),
        )
    except Exception:
        pass


# ── 2) Diagnose raw ──────────────────────────────────────────────────────

def _tui_diagnose_raw():
    console.print("[cyan]Paste the error message (press Enter twice to submit):[/cyan]")
    lines: list[str] = []
    while True:
        line = input()
        if line == "":
            break
        lines.append(line)
    error_text = "\n".join(lines).strip()
    if not error_text:
        console.print("[yellow]No input provided.[/yellow]")
        return

    cfg = load_config()
    from crashsense.core.tx_analyzer import TxAnalyzer

    analyzer = TxAnalyzer(provider=cfg.get("provider", "gemini"))

    with console.status("[cyan]Analyzing error text…[/cyan]"):
        result = analyzer.diagnose_raw(error_text)

    _render_result(result)


# ── 3) Switch chain ──────────────────────────────────────────────────────

def _tui_switch_chain():
    cfg = load_config()
    current = cfg.get("chain", {}).get("name", "ethereum")
    console.print(f"[dim]Current chain: {current}[/dim]")

    table = Table(title="Available Chains")
    table.add_column("Name", style="cyan")
    table.add_column("Chain ID")
    table.add_column("Currency")

    for name, info in SUPPORTED_CHAINS.items():
        table.add_row(name, str(info["chain_id"]), info["currency"])

    console.print(table)

    choice = Prompt.ask("Select chain", choices=list(SUPPORTED_CHAINS.keys()), default=current)
    cfg.setdefault("chain", {})["name"] = choice
    save_config(cfg)
    console.print(f"[green]✓ Switched to {choice}[/green]")


# ── 4) Switch provider ───────────────────────────────────────────────────

def _tui_switch_provider():
    cfg = load_config()
    current = cfg.get("provider", "gemini")
    console.print(f"[dim]Current provider: {current}[/dim]")

    providers = ["gemini", "openai", "claude", "ollama"]
    for p in providers:
        key = get_api_key(p)
        status = "[green]key set[/green]" if key else "[yellow]no key[/yellow]"
        if p == "ollama":
            status = "[green]local[/green]"
        marker = " ← active" if p == current else ""
        console.print(f"  • {p} ({status}){marker}")

    choice = Prompt.ask("Select provider", choices=providers, default=current)
    cfg["provider"] = choice
    save_config(cfg)
    console.print(f"[green]✓ Switched to {choice}[/green]")


# ── 5) History ────────────────────────────────────────────────────────────

def _tui_history():
    from crashsense.core.memory import MemoryStore

    mem = MemoryStore()
    items = mem.list_recent(15)
    if not items:
        console.print("[dim]No diagnoses recorded yet.[/dim]")
        return

    table = Table(title="Diagnosis History")
    table.add_column("Tx Hash", style="cyan", max_width=20)
    table.add_column("Chain")
    table.add_column("Root Cause", style="yellow")
    table.add_column("Status")
    table.add_column("Date", style="dim")

    for item in items:
        short = item.tx_hash[:10] + "…" + item.tx_hash[-6:]
        table.add_row(
            short,
            item.chain or "",
            (item.root_cause or "")[:40],
            item.status or "",
            str(item.created_at)[:19] if item.created_at else "",
        )

    console.print(table)


# ── 6) Configuration ─────────────────────────────────────────────────────

def _tui_config():
    import toml as toml_mod

    cfg = load_config()
    text = toml_mod.dumps(cfg)
    console.print(Panel(text, title="Current Configuration", border_style="cyan"))


# ── Shared rendering ─────────────────────────────────────────────────────

def _render_result(result: dict):
    """Render a diagnosis result in the TUI."""
    from crashsense.core.remediation import RemediationEngine

    tx_ctx = result.get("tx_context", {})
    analysis = result.get("analysis", {})
    patterns = result.get("patterns_matched", [])

    if tx_ctx and "error" not in tx_ctx:
        table = Table(title="Transaction Summary", show_lines=True)
        table.add_column("Field", style="cyan")
        table.add_column("Value")

        fields = [
            ("Tx Hash", tx_ctx.get("tx_hash", "")),
            ("Chain", tx_ctx.get("chain", "")),
            ("From", tx_ctx.get("from", "")),
            ("To", tx_ctx.get("to", "")),
            ("Value", f"{tx_ctx.get('value_eth', 0)} {tx_ctx.get('currency', 'ETH')}"),
            ("Function", tx_ctx.get("function_called", "")),
            ("Gas", f"{tx_ctx.get('gas_used', 0):,} / {tx_ctx.get('gas_limit', 0):,} ({tx_ctx.get('gas_utilisation_pct', 0):.1f}%)"),
            ("Status", tx_ctx.get("status", "")),
            ("Revert Reason", tx_ctx.get("revert_reason", "") or "—"),
        ]
        for name, val in fields:
            table.add_row(name, str(val))
        console.print(table)

    if patterns:
        console.print(f"\n[bold]Patterns matched:[/bold] {', '.join(patterns)}")

    console.print(Panel(
        f"[bold]Root Cause:[/bold] {analysis.get('root_cause', 'Unknown')}\n\n"
        f"{analysis.get('explanation', 'No explanation available.')}\n\n"
        f"[bold]Suggested Fix:[/bold] {analysis.get('suggested_fix', '—')}",
        title="[bold cyan]Diagnosis[/bold cyan]",
        border_style="green",
    ))

    if patterns:
        engine = RemediationEngine()
        fixes_text = engine.format_fixes(patterns)
        console.print(Panel(fixes_text, title="[bold]Remediation Steps[/bold]", border_style="yellow"))
