"""CLI implementation for `antiqa test "..."` — natural language test input."""

from __future__ import annotations

from pathlib import Path

import typer
import yaml
from rich.console import Console
from rich.panel import Panel
from rich.table import Table

from antiqa.config.manager import config_exists, load_config

console = Console()


def run_natural_test(
    description: str,
    headed: bool | None = None,
    save: bool = False,
) -> None:
    """Generate and execute a test flow from a plain English description."""
    if not config_exists():
        console.print("[red]No antiqa.json found. Run [bold]antiqa init[/bold] first.[/red]")
        raise typer.Exit(code=2)

    config = load_config()
    if headed is not None:
        config.browser.headless = not headed

    from antiqa.agents.natural_test import NaturalTestAgent
    from antiqa.browser.manager import BrowserManager
    from antiqa.crawler.graph import NavigationGraph
    from antiqa.flows.runner import FlowRunner

    console.print()
    console.print(Panel(
        f"[bold cyan]AntiQA[/bold cyan]  ·  AI Test\n"
        f"[dim]\"{description}\"[/dim]",
        border_style="cyan",
        expand=False,
    ))

    graph = None
    graph_path = Path("logs/navigation_graph.json")
    if graph_path.is_file():
        graph = NavigationGraph.load(graph_path)

    with console.status("[cyan]AI is generating test flow..."):
        agent = NaturalTestAgent(config, graph=graph)
        try:
            flow = agent.generate(description)
        except Exception as exc:
            console.print(f"\n[red]AI generation failed:[/red] {exc}")
            console.print("[dim]Make sure your LLM API key is set correctly.[/dim]")
            raise typer.Exit(code=2)

    console.print(f"\n  [green]✓[/green] Generated flow: [cyan]{flow.name}[/cyan]")
    console.print(f"    {flow.description}")
    console.print(f"    {len(flow.steps)} steps, {len(flow.assertions)} assertions\n")

    # Show the plan
    plan_table = Table(show_header=True, header_style="bold dim", expand=False, title="Generated Steps")
    plan_table.add_column("#", width=4, justify="right")
    plan_table.add_column("Action", style="cyan")
    plan_table.add_column("Description")
    plan_table.add_column("Details", style="dim")

    for i, step in enumerate(flow.steps, 1):
        details = step.selector or step.url or step.value or ""
        if len(details) > 40:
            details = details[:37] + "..."
        plan_table.add_row(str(i), step.action, step.description, details)

    console.print(plan_table)
    console.print()

    if save:
        flow_path = Path(config.flows_dir) / f"{flow.name}.yaml"
        flow_data = {
            "name": flow.name,
            "description": flow.description,
            "steps": [_step_to_dict(s) for s in flow.steps],
        }
        if flow.assertions:
            flow_data["assertions"] = [_assertion_to_dict(a) for a in flow.assertions]
        flow_path.write_text(yaml.dump(flow_data, default_flow_style=False, sort_keys=False))
        console.print(f"  [green]✓[/green] Saved flow to [cyan]{flow_path}[/cyan]\n")

    # Execute
    console.print("[cyan]Executing...[/cyan]\n")

    mgr = BrowserManager(config.browser, logs_dir=config.logs_dir)
    page = mgr.launch()

    try:
        runner = FlowRunner(page, config=config, screenshots_dir=f"{config.logs_dir}/screenshots")
        result = runner.run(flow)
    finally:
        mgr.close()

    from antiqa.utils.cleanup import remove_screenshots
    remove_screenshots(f"{config.logs_dir}/screenshots")

    # Results
    result_table = Table(show_header=True, header_style="bold", expand=False)
    result_table.add_column("#", width=4, justify="right", style="dim")
    result_table.add_column("Action")
    result_table.add_column("Description")
    result_table.add_column("Status")
    result_table.add_column("Time", justify="right")

    for sr in result.steps:
        status = "[green]PASS[/green]" if sr.passed else "[red]FAIL[/red]"
        result_table.add_row(
            str(sr.step_number), sr.action, sr.description[:60], status,
            f"{sr.action_result.duration_ms:.0f}ms",
        )

    console.print(result_table)

    if result.assertions:
        console.print()
        a_table = Table(title="Assertions", expand=False)
        a_table.add_column("Type")
        a_table.add_column("Expected")
        a_table.add_column("Actual")
        a_table.add_column("Status")
        for ar in result.assertions:
            status = "[green]PASS[/green]" if ar.passed else "[red]FAIL[/red]"
            a_table.add_row(ar.type, ar.expected[:40], ar.actual[:40], status)
        console.print(a_table)

    if result.health_issues:
        console.print(f"\n  [yellow]⚠ {len(result.health_issues)} health issue(s) detected[/yellow]")

    console.print()
    s = result.summary()
    if result.passed:
        console.print(Panel(
            f"[bold green]PASSED[/bold green]  ✅\n"
            f"Steps: {s['steps_passed']}/{s['steps_total']}  |  Time: {s['duration_ms']:.0f}ms",
            border_style="green",
            expand=False,
        ))
    else:
        console.print(Panel(
            f"[bold red]FAILED[/bold red]  ❌\n"
            f"Steps: {s['steps_passed']}/{s['steps_total']}  |  Time: {s['duration_ms']:.0f}ms\n"
            f"[dim]{s['error'] or ''}[/dim]",
            border_style="red",
            expand=False,
        ))
        raise typer.Exit(code=1)


def _step_to_dict(step) -> dict:
    d: dict = {"action": step.action}
    if step.url:
        d["url"] = step.url
    if step.selector:
        d["selector"] = step.selector
    if step.value:
        d["value"] = step.value
    if step.key:
        d["key"] = step.key
    if step.name:
        d["name"] = step.name
    if step.timeout_ms:
        d["timeout_ms"] = step.timeout_ms
    if step.direction:
        d["direction"] = step.direction
    if step.description:
        d["description"] = step.description
    return d


def _assertion_to_dict(a) -> dict:
    d: dict = {"type": a.type}
    if a.value:
        d["value"] = a.value
    if a.selector:
        d["selector"] = a.selector
    return d
