from __future__ import annotations

import asyncio
import json
from pathlib import Path
from typing import Annotated

import click
import typer

from cleveragents.cli.commands._resolve_actor import (
    resolve_config_files as _resolve_config_files,
)
from cleveragents.core.exceptions import (
    CleverAgentsError,
    UnsafeConfigurationError,
)
from cleveragents.reactive.application import ReactiveCleverAgentsApp
from cleveragents.reactive.context_manager import ContextManager

app = typer.Typer(help="Run reactive configs with actor-first semantics.")


@app.command()
def run(
    name: Annotated[
        str,
        typer.Argument(help="Actor name to run (resolved from actor registry)"),
    ],
    prompt: Annotated[
        str,
        typer.Argument(help="Prompt text to send to the actor"),
    ],
    config: Annotated[
        list[Path] | None,
        typer.Option(
            "--config",
            "-c",
            exists=True,
            file_okay=True,
            dir_okay=False,
            readable=True,
            resolve_path=True,
            help="YAML config paths (overrides registry-based name resolution)",
        ),
    ] = None,
    output: Annotated[
        Path | None,
        typer.Option(
            "--output",
            "-o",
            file_okay=True,
            dir_okay=False,
            writable=True,
            resolve_path=True,
        ),
    ] = None,
    verbose: Annotated[int, typer.Option("--verbose", "-v", count=True)] = 0,
    unsafe: Annotated[
        bool, typer.Option("--unsafe", "-u", help="Confirm unsafe configs")
    ] = False,
    context: Annotated[
        str | None, typer.Option("--context", help="Name for saving/reusing context")
    ] = None,
    context_dir: Annotated[
        Path | None,
        typer.Option(
            "--context-dir", help="Directory to store context data", resolve_path=True
        ),
    ] = None,
    load_context: Annotated[
        Path | None,
        typer.Option(
            "--load-context",
            exists=True,
            file_okay=True,
            dir_okay=False,
            resolve_path=True,
            help="Load context from JSON; imports into named context when provided",
        ),
    ] = None,
    temperature: Annotated[
        float | None, typer.Option("--temperature", "-t", help="Override temperature")
    ] = None,
    allow_rxpy_in_run_mode: Annotated[
        bool,
        typer.Option(
            "--allow-rxpy-in-run-mode",
            help="Allow RxPy stream routes in run mode (bypass validation)",
        ),
    ] = False,
    skill: Annotated[
        list[str] | None,
        typer.Option(
            "--skill",
            metavar="NAME",
            help="Skill to attach; only augments tool-bearing agents (repeatable)",
        ),
    ] = None,
) -> None:
    """Run the reactive network once with actor-first configs."""
    try:
        resolved_config = _resolve_config_files(name, list(config or []))
        app_exec = ReactiveCleverAgentsApp(
            config_files=resolved_config,
            verbose=verbose,
            unsafe=unsafe,
            temperature_override=temperature,
            skill_names=skill,
        )

        async def _execute() -> str:
            if load_context and context:
                ctx_mgr = ContextManager(context, context_dir)
                ctx_mgr.import_context(load_context)
                if ctx_mgr.global_context and app_exec.config:
                    app_exec.config.global_context.update(ctx_mgr.global_context)
                ctx_mgr.add_message("user", prompt)
                result = await app_exec.run_single_shot(
                    prompt,
                    context_manager=ctx_mgr,
                    allow_rxpy_in_run_mode=allow_rxpy_in_run_mode,
                )
                ctx_mgr.add_message("assistant", result)
                if app_exec.config:
                    ctx_mgr.save_global_context(app_exec.config.global_context)
                return result
            if load_context:
                with open(load_context, encoding="utf-8") as f:
                    data = json.load(f)
                if data.get("global_context") and app_exec.config:
                    app_exec.config.global_context.update(data["global_context"])
                return await app_exec.run_single_shot(
                    prompt,
                    context_manager=None,
                    allow_rxpy_in_run_mode=allow_rxpy_in_run_mode,
                )
            if context:
                ctx_mgr = ContextManager(context, context_dir)
                if ctx_mgr.exists() and ctx_mgr.global_context and app_exec.config:
                    app_exec.config.global_context.update(ctx_mgr.global_context)
                ctx_mgr.add_message("user", prompt)
                result = await app_exec.run_single_shot(
                    prompt,
                    context_manager=ctx_mgr,
                    allow_rxpy_in_run_mode=allow_rxpy_in_run_mode,
                )
                ctx_mgr.add_message("assistant", result)
                if app_exec.config:
                    ctx_mgr.save_global_context(app_exec.config.global_context)
                return result
            return await app_exec.run_single_shot(
                prompt,
                context_manager=None,
                allow_rxpy_in_run_mode=allow_rxpy_in_run_mode,
            )

        result = asyncio.run(_execute())
    except UnsafeConfigurationError as exc:
        typer.echo(f"Error: {exc}", err=True)
        raise typer.Exit(code=1) from exc
    except click.exceptions.Exit:
        raise
    except CleverAgentsError as exc:
        typer.echo(f"Error: {exc}", err=True)
        raise typer.Exit(code=2) from exc
    except Exception as exc:  # pragma: no cover
        typer.echo(f"Unexpected error: {exc}", err=True)
        raise typer.Exit(code=3) from exc

    if output:
        output.write_text(result)
        typer.echo(f"Output written to {output}")
    else:
        typer.echo(result)
