"""Experiment commands."""

import click
from rich.console import Console
from rich.table import Table
from rich.panel import Panel
from rich.progress import Progress, SpinnerColumn, TextColumn
import time

from ..client import AIandMeClient
from ..exceptions import NotAuthenticatedError, APIError, ValidationError

console = Console()


@click.group("experiments")
def experiments_group():
    """Experiment management commands."""
    pass


@experiments_group.command("list")
@click.option("--page", default=1, help="Page number")
@click.option("--size", default=20, help="Items per page")
def list_experiments(page: int, size: int):
    """List experiments in the current project."""
    client = AIandMeClient()

    if not client.project_id:
        console.print("[yellow]No project selected.[/yellow]")
        console.print("Use 'aiandme projects use <id>' to select a project first.")
        raise SystemExit(1)

    try:
        response = client.list_experiments(page=page, size=size)
        experiments = response.get("data", [])

        if not experiments:
            console.print("[yellow]No experiments found.[/yellow]")
            return

        table = Table(title="Experiments")
        table.add_column("ID", style="dim")
        table.add_column("Name", style="bold")
        table.add_column("Status")
        table.add_column("Test Category")
        table.add_column("Created")

        for exp in experiments:
            status = exp.get("status", "Unknown")
            status_style = {
                "Finished": "[green]Finished[/green]",
                "Running": "[yellow]Running[/yellow]",
                "Failed": "[red]Failed[/red]",
                "Generating": "[cyan]Generating[/cyan]",
                "Generated": "[blue]Generated[/blue]",
            }.get(status, status)

            table.add_row(
                exp.get("id", ""),
                exp.get("name", "Unknown"),
                status_style,
                exp.get("test_category", "").split("/")[-1],
                exp.get("created_at", "")[:10],
            )

        console.print(table)

        if response.get("has_next_page"):
            console.print(f"\n[dim]Page {page} of more. Use --page to navigate.[/dim]")

    except NotAuthenticatedError:
        console.print("[red]Not authenticated.[/red] Run 'aiandme login' first.")
        raise SystemExit(1)
    except APIError as e:
        console.print(f"[red]Error:[/red] {e}")
        raise SystemExit(1)


@experiments_group.command("show")
@click.argument("experiment_id")
def show_experiment(experiment_id: str):
    """Show experiment details.

    EXPERIMENT_ID: Experiment UUID.
    """
    client = AIandMeClient()

    if not client.project_id:
        console.print("[yellow]No project selected.[/yellow]")
        raise SystemExit(1)

    try:
        exp = client.get_experiment(experiment_id)

        status = exp.get("status", "Unknown")
        status_color = {
            "Finished": "green",
            "Running": "yellow",
            "Failed": "red",
        }.get(status, "white")

        console.print(Panel(
            f"[bold]{exp.get('name')}[/bold]\n"
            f"[dim]ID: {exp.get('id')}[/dim]\n\n"
            f"Status: [{status_color}]{status}[/{status_color}]\n"
            f"Test Category: {exp.get('test_category')}\n"
            f"Language: {exp.get('lang', 'en')}\n"
            f"Testing Level: {exp.get('testing_level', 'unit')}",
            title="Experiment Details",
        ))

        results = exp.get("results", {})
        if results and results.get("insights"):
            console.print("\n[bold]Results:[/bold]")
            stats = results.get("stats", {})
            if stats:
                console.print(f"  Total logs: {stats.get('total', 0)}")
                console.print(f"  Pass: {stats.get('pass', 0)}")
                console.print(f"  Fail: {stats.get('fail', 0)}")

            insights = results.get("insights", [])
            if insights:
                console.print(f"\n  Insights: {len(insights)} findings")
                for i, insight in enumerate(insights[:3], 1):
                    console.print(f"    {i}. {insight.get('explanation', '')[:80]}...")

    except NotAuthenticatedError:
        console.print("[red]Not authenticated.[/red] Run 'aiandme login' first.")
        raise SystemExit(1)
    except APIError as e:
        console.print(f"[red]Error:[/red] {e}")
        raise SystemExit(1)


@experiments_group.command("status")
@click.argument("experiment_id")
@click.option("--watch", "-w", is_flag=True, help="Watch status until completion")
@click.option("--interval", default=10, help="Polling interval in seconds (with --watch)")
def experiment_status(experiment_id: str, watch: bool, interval: int):
    """Check experiment status.

    EXPERIMENT_ID: Experiment UUID.
    """
    client = AIandMeClient()

    if not client.project_id:
        console.print("[yellow]No project selected.[/yellow]")
        raise SystemExit(1)

    try:
        if not watch:
            status = client.get_experiment_status(experiment_id)
            _print_status(status)
            return

        # Watch mode
        with Progress(
            SpinnerColumn(),
            TextColumn("[progress.description]{task.description}"),
            console=console,
        ) as progress:
            task = progress.add_task("Watching experiment...", total=None)

            while True:
                status = client.get_experiment_status(experiment_id)
                current_status = status.get("status", "Unknown")

                progress.update(task, description=f"Status: {current_status}")

                if current_status in TERMINAL_STATUSES:
                    break

                time.sleep(interval)

        _print_status(status)

        if current_status == "Finished":
            console.print("\n[green]Experiment completed successfully![/green]")
        else:
            console.print(f"\n[red]Experiment ended with status: {current_status}[/red]")

    except NotAuthenticatedError:
        console.print("[red]Not authenticated.[/red] Run 'aiandme login' first.")
        raise SystemExit(1)
    except APIError as e:
        console.print(f"[red]Error:[/red] {e}")
        raise SystemExit(1)
    except KeyboardInterrupt:
        console.print("\n[yellow]Stopped watching.[/yellow]")


def _print_status(status: dict):
    """Print experiment status."""
    current_status = status.get("status", "Unknown")
    status_color = {
        "Finished": "green",
        "Running": "yellow",
        "Failed": "red",
        "Generating": "cyan",
        "Generated": "blue",
    }.get(current_status, "white")

    console.print(f"Status: [{status_color}]{current_status}[/{status_color}]")


TERMINAL_STATUSES = ["Finished", "Failed"]


@experiments_group.command("wait")
@click.argument("experiment_id")
@click.option("--timeout", default=120, help="Max wait time in minutes (default: 120)")
def experiment_wait(experiment_id: str, timeout: int):
    """Wait for an experiment to complete.

    Polls experiment status with progressive backoff:
    starts at every 30s, increases to every 5 minutes.

    Returns exit code 0 on Finished, 1 on Failed.

    EXPERIMENT_ID: Experiment UUID.
    """
    client = AIandMeClient()

    if not client.project_id:
        console.print("[yellow]No project selected.[/yellow]")
        raise SystemExit(1)

    try:
        start_time = time.time()
        timeout_seconds = timeout * 60
        poll_interval = 30  # start at 30s
        max_interval = 300  # cap at 5 minutes

        console.print(f"Waiting for experiment {experiment_id} (timeout: {timeout}m)\n")

        while True:
            elapsed = time.time() - start_time
            if elapsed > timeout_seconds:
                console.print(f"\n[red]Timeout after {timeout} minutes.[/red]")
                raise SystemExit(1)

            status_response = client.get_experiment_status(experiment_id)
            current_status = status_response.get("status", "Unknown")

            minutes_elapsed = int(elapsed / 60)
            seconds_elapsed = int(elapsed % 60)
            console.print(
                f"  [{minutes_elapsed:02d}:{seconds_elapsed:02d}] Status: {current_status}"
                f"  (next check in {poll_interval}s)"
            )

            if current_status in TERMINAL_STATUSES:
                console.print()
                _print_status(status_response)

                if current_status == "Finished":
                    console.print("[green]Experiment completed successfully![/green]")
                    return
                else:
                    console.print(f"[red]Experiment ended: {current_status}[/red]")
                    raise SystemExit(1)

            time.sleep(poll_interval)

            # Progressive backoff: 30s → 60s → 120s → 300s
            poll_interval = min(poll_interval * 2, max_interval)

    except NotAuthenticatedError:
        console.print("[red]Not authenticated.[/red] Run 'aiandme login' first.")
        raise SystemExit(1)
    except APIError as e:
        console.print(f"[red]Error:[/red] {e}")
        raise SystemExit(1)
    except KeyboardInterrupt:
        console.print("\n[yellow]Stopped waiting. Experiment continues in background.[/yellow]")
        console.print(f"Resume with: aiandme experiments wait {experiment_id}")
        raise SystemExit(0)


@experiments_group.command("logs")
@click.argument("experiment_id")
@click.option("--page", default=1, help="Page number")
@click.option("--size", default=20, help="Items per page")
@click.option("--result", type=click.Choice(["pass", "fail"]), help="Filter by result")
def experiment_logs(experiment_id: str, page: int, size: int, result: str):
    """List logs for an experiment.

    EXPERIMENT_ID: Experiment UUID.
    """
    client = AIandMeClient()

    if not client.project_id:
        console.print("[yellow]No project selected.[/yellow]")
        raise SystemExit(1)

    try:
        response = client.get_experiment_logs(
            experiment_id,
            page=page,
            size=size,
            result=result,
        )
        logs = response.get("data", [])

        if not logs:
            console.print("[yellow]No logs found.[/yellow]")
            return

        table = Table(title=f"Experiment Logs (page {page})")
        table.add_column("ID", style="dim")
        table.add_column("Result")
        table.add_column("Severity")
        table.add_column("Category")
        table.add_column("Prompt", max_width=40)

        for log in logs:
            result_val = log.get("result", "")
            result_style = "[green]pass[/green]" if result_val == "pass" else "[red]fail[/red]"

            table.add_row(
                log.get("id", ""),
                result_style,
                str(log.get("severity", "")),
                log.get("fail_category") or log.get("gen_category") or "",
                (log.get("prompt", "") or "")[:40],
            )

        console.print(table)

        if response.get("has_next_page"):
            console.print(f"\n[dim]Use --page to see more results.[/dim]")

    except NotAuthenticatedError:
        console.print("[red]Not authenticated.[/red] Run 'aiandme login' first.")
        raise SystemExit(1)
    except APIError as e:
        console.print(f"[red]Error:[/red] {e}")
        raise SystemExit(1)


@experiments_group.command("report")
@click.argument("experiment_id")
@click.option("--output", "-o", type=click.Path(), help="Output file path")
def experiment_report(experiment_id: str, output: str):
    """Download experiment report.

    EXPERIMENT_ID: Experiment UUID.
    """
    client = AIandMeClient()

    if not client.project_id:
        console.print("[yellow]No project selected.[/yellow]")
        raise SystemExit(1)

    try:
        with console.status("Generating report..."):
            report_html = client.get_experiment_report(experiment_id)

        if output:
            with open(output, "w") as f:
                f.write(report_html)
            console.print(f"[green]Report saved to:[/green] {output}")
        else:
            # Default filename
            filename = f"experiment_{experiment_id}_report.html"
            with open(filename, "w") as f:
                f.write(report_html)
            console.print(f"[green]Report saved to:[/green] {filename}")

    except NotAuthenticatedError:
        console.print("[red]Not authenticated.[/red] Run 'aiandme login' first.")
        raise SystemExit(1)
    except APIError as e:
        console.print(f"[red]Error:[/red] {e}")
        raise SystemExit(1)
