"""Agent CLI commands - run, chat, test, describe."""
from __future__ import annotations

import asyncio
from pathlib import Path
from typing import TYPE_CHECKING, Any

import click

from logos_adk.runnable_config_loader import (
    describe_runnable_from_config,
    load_runnable_from_config,
)

from ..utils.animation import run_with_animation
from ..utils.output import write_result_output
from ..utils.validation import validate_config_file

if TYPE_CHECKING:
    pass


async def _stream_response(agent: Any, prompt: str, session_id: str | None) -> None:
    """Stream agent response to terminal."""
    import click
    
    async for chunk in agent.stream(prompt, session_id=session_id):
        chunk_type = getattr(chunk, "type", None)
        if chunk_type == "text":
            text = getattr(chunk, "text", "") or getattr(chunk, "delta", "")
            if text:
                click.echo(text, nl=False)


def _compat_loader():
    import logos_adk.cli as cli_module

    return getattr(cli_module, "load_runnable_from_config", load_runnable_from_config)


def _compat_describer():
    import logos_adk.cli as cli_module

    return getattr(cli_module, "describe_runnable_from_config", describe_runnable_from_config)


def _compat_animation():
    import logos_adk.cli as cli_module

    return getattr(cli_module, "_run_with_animation", run_with_animation)


@click.command()
@click.argument("config", type=click.Path(exists=True, path_type=Path), callback=validate_config_file)
@click.argument("prompt")
@click.option("--session-id", "-s", help="Session ID for context")
@click.option("--stream", is_flag=True, help="Enable streaming output")
@click.option("--output", "-o", type=click.Path(path_type=Path), help="Write JSON/YAML output")
def run(config: Path, prompt: str, session_id: str | None, stream: bool, output: Path | None) -> None:
    """Run a runnable from CONFIG with a single PROMPT."""
    agent = _compat_loader()(str(config))
    
    kwargs: dict[str, Any] = {"prompt": prompt}
    if session_id:
        kwargs["session_id"] = session_id
    
    if stream:
        asyncio.run(_stream_response(agent, prompt, session_id))
        click.echo()
    else:
        async def run_agent():
            return await agent.run(**kwargs)
        
        response = asyncio.run(_compat_animation()(run_agent(), "Thinking"))
        
        if hasattr(response, "reasoning") and response.reasoning:
            click.echo(click.style("\n🤔 Reasoning:\n", fg="cyan", bold=True))
            click.echo(click.style(response.reasoning, fg="cyan"))
        
        click.echo(response.content)
        
        if hasattr(response, "usage") and response.usage:
            click.echo(
                click.style(
                    f"\n[Tokens: {response.usage.input_tokens} in, {response.usage.output_tokens} out]",
                    fg="yellow",
                )
            )
        
        # Write output if requested
        write_result_output(output, {
            "content": response.content,
            "reasoning": getattr(response, "reasoning", None),
            "usage": {
                "input_tokens": getattr(getattr(response, "usage", None), "input_tokens", 0),
                "output_tokens": getattr(getattr(response, "usage", None), "output_tokens", 0),
            } if hasattr(response, "usage") else None,
        })


@click.command()
@click.argument("config", type=click.Path(exists=True, path_type=Path), callback=validate_config_file)
def chat(config: Path) -> None:
    """Start an interactive chat with a runnable from CONFIG file."""
    agent = _compat_loader()(str(config))
    agent_name = _compat_describer()(str(config))["name"]
    session_id = click.prompt("Session ID (or Enter for new)", default="", show_default=False)
    
    click.echo(f"Starting chat with agent: {agent_name}")
    click.echo("Type 'exit' or 'quit' to stop, 'clear' to clear history\n")
    
    history: list[str] = []
    sess_id = session_id if session_id else None
    
    while True:
        try:
            user_input = click.prompt("You", type=str, default="")
            
            if user_input.lower() in ("exit", "quit"):
                click.echo("Goodbye!")
                break
            
            if user_input.lower() == "clear":
                history.clear()
                click.echo("History cleared.\n")
                continue
            
            if not user_input.strip():
                continue
            
            history.append(f"User: {user_input}")
            
            async def run_agent():
                response = await agent.run(user_input, session_id=sess_id)
                return response
            
            response = asyncio.run(_compat_animation()(run_agent(), "Thinking"))
            
            if hasattr(response, "reasoning") and response.reasoning:
                click.echo(click.style("\n🤔 Reasoning:\n", fg="cyan", bold=True))
                click.echo(click.style(response.reasoning, fg="cyan"))
            
            click.echo(f"\n\n{click.style('Agent:', fg='green', bold=True)} {response.content}\n")
            history.append(f"Agent: {response.content}")
            
            if hasattr(response, "usage") and response.usage:
                click.echo(
                    click.style(
                        f"[Tokens: {response.usage.input_tokens} in, {response.usage.output_tokens} out]",
                        fg="yellow",
                    )
                    + "\n"
                )
        
        except KeyboardInterrupt:
            click.echo("\nGoodbye!")
            break
        except Exception as e:
            click.echo(click.style(f"Error: {e}", fg="red", err=True), err=True)


@click.command()
@click.argument("config", type=click.Path(exists=True, path_type=Path), callback=validate_config_file)
def validate(config: Path) -> None:
    """Validate agent CONFIG file."""
    from logos_adk.config_loader import load_agent_config
    
    try:
        config_data = load_agent_config(str(config))
        click.echo(f"✓ Config valid: {config}")
        
        name = getattr(config_data, "name", "unnamed")
        model = getattr(config_data, "model", "not set")
        
        click.echo(f"  Name: {name}")
        click.echo(f"  Model: {model}")
        
        provider = getattr(config_data, "provider", None)
        if provider:
            ptype = getattr(provider, "type", "unknown")
            pmodel = getattr(provider, "model", None)
            pbase = getattr(provider, "base_url", None)
            click.echo(f"  Provider: {ptype}")
            if pmodel:
                click.echo(f"    Model: {pmodel}")
            if pbase:
                click.echo(f"    Base URL: {pbase}")
        
        tools = getattr(config_data, "tools", []) or []
        click.echo(f"  Tools: {len(tools)}")
        
        memory = getattr(config_data, "memory", None)
        if memory:
            mem_type = getattr(memory, "type", "unknown")
        else:
            mem_type = "none"
        click.echo(f"  Memory: {mem_type}")
        
        mcp = getattr(config_data, "mcp", []) or []
        click.echo(f"  MCP servers: {len(mcp)}")
        
        observe = getattr(config_data, "observe", None)
        if observe:
            obs_exp = getattr(observe, "exporter", "enabled")
            click.echo(f"  Observability: {obs_exp}")
    
    except Exception as e:
        click.echo(click.style(f"✗ Invalid config: {e}", fg="red", err=True), err=True)
        raise SystemExit(1)


@click.command()
@click.argument("config", type=click.Path(exists=True, path_type=Path), callback=validate_config_file)
@click.option("--output", "-o", type=click.Path(path_type=Path), help="Write JSON/YAML output")
def describe(config: Path, output: Path | None) -> None:
    """Describe runnable from CONFIG file."""
    result = _compat_describer()(str(config))
    
    click.echo(f"Runnable: {result.get('name', 'unknown')}")
    click.echo(f"  Type: {result.get('type', 'unknown')}")
    click.echo(f"  Model: {result.get('model', 'unknown')}")
    
    if result.get("system_prompt"):
        click.echo(f"  System Prompt: {result['system_prompt'][:100]}...")
    
    if result.get("tools"):
        click.echo(f"  Tools: {len(result['tools'])}")
    
    if result.get("memories"):
        click.echo(f"  Memories: {len(result['memories'])}")
    
    # Write output if requested
    write_result_output(output, result)


@click.command(name="tui")
@click.argument("config", type=click.Path(exists=True, path_type=Path), callback=validate_config_file)
def tui_ide_command(config: Path) -> None:
    """Start the full Terminal IDE (Cline-style) for CONFIG."""
    from ..tui import LogosTUI
    
    app = LogosTUI(str(config))
    app.run()


@click.command(name="test")
@click.argument("config", type=click.Path(exists=True, path_type=Path), callback=validate_config_file)
@click.option("--prompt", default="Hello", show_default=True, help="Test prompt")
def test_command(config: Path, prompt: str) -> None:
    """Test runnable connectivity and basic execution."""
    loader = _compat_loader()
    describer = _compat_describer()

    metadata = describer(str(config))
    click.echo(f"Loaded {metadata.get('kind', 'runnable')} from config: {metadata.get('name', config.stem)}")
    click.echo(f'Sending test prompt: "{prompt}"')

    agent = loader(str(config))

    async def run_agent():
        return await agent.run(prompt)

    response = asyncio.run(_compat_animation()(run_agent(), "Testing"))
    click.echo("\nTest successful")
    click.echo(response.content)


__all__ = ["run", "chat", "validate", "describe", "tui_ide_command", "test_command"]
