"""
ZIA CLI — developer-facing commands for scaffolding, validating, and running agents.

Commands:
  zia init --name <name> --domain <domain>  — scaffold a new agent (YAML + Python class)
  zia validate <path>                        — validate a YAML agent definition
  zia run <path> --tenant <id>               — run an agent in a tenant context
  zia agents                                 — list all registered agent classes
  zia info                                   — show ZIA version and config
"""

from __future__ import annotations

import re
import sys
from pathlib import Path

import click
from rich.console import Console
from rich.panel import Panel
from rich.table import Table

import zia
from zia.core.dsl.parser import load_agent_yaml, validate_agent

console = Console()


@click.group()
@click.version_option(zia.__version__, prog_name="zia")
def cli() -> None:
    """ZIA — Zeron Universal Security Agent Development Kit."""


@cli.command(name="init")
@click.option("--name", "-n", required=True, help="Human-readable agent name (e.g. 'My Risk Agent')")
@click.option(
    "--domain", "-d", required=True,
    type=click.Choice(["risk_quant", "supply_chain", "red_team", "appsec", "ai_security", "compliance"]),
    help="Security domain for this agent",
)
@click.option("--out", "-o", default=".", show_default=True, help="Output directory")
def init(name: str, domain: str, out: str) -> None:
    """Scaffold a new agent — generates a YAML definition and Python class."""
    from zia.cli.templates import DOMAIN_TEMPLATES

    tmpl = DOMAIN_TEMPLATES[domain]

    # Derive safe ID and class name from the human name
    agent_id = re.sub(r"[^a-z0-9]+", "-", name.lower()).strip("-")
    class_name = "".join(w.capitalize() for w in re.split(r"[^a-zA-Z0-9]+", name))
    if not class_name.endswith("Agent"):
        class_name += "Agent"

    out_dir = Path(out)
    out_dir.mkdir(parents=True, exist_ok=True)

    yaml_path = out_dir / f"{agent_id}.yaml"
    python_path = out_dir / f"{agent_id.replace('-', '_')}.py"

    yaml_path.write_text(tmpl.yaml_template.format(agent_id=agent_id, agent_name=name))
    python_path.write_text(tmpl.python_template.format(
        agent_id=agent_id, agent_name=name, class_name=class_name
    ))

    result = validate_agent(yaml_path)

    console.print(Panel(
        f"[bold green]✅ Agent scaffolded![/bold green]\n\n"
        f"[bold]YAML:[/bold]   [cyan]{yaml_path}[/cyan]\n"
        f"[bold]Class:[/bold]  [cyan]{python_path}[/cyan]\n\n"
        f"[bold]Next:[/bold]\n"
        f"  1. Implement [cyan]{class_name}.execute()[/cyan]\n"
        f"  2. [white]zia validate {yaml_path}[/white]\n"
        f"  3. [white]zia run {yaml_path} --tenant <id>[/white]",
        title=f"[bold blue]🚀 zia init — {name}[/bold blue]",
        border_style="blue",
    ))

    if not result.valid:
        console.print("[yellow]⚠ Validation warnings in generated YAML:[/yellow]")
        for e in result.errors:
            console.print(f"  [yellow]• {e}[/yellow]")


@cli.command()
@click.argument("path", type=click.Path(exists=True))
def validate(path: str) -> None:
    """Validate a US-ADSL agent YAML definition."""
    result = validate_agent(path)
    if result.valid:
        console.print(
            Panel(
                f"[bold green]✅ Valid[/bold green] — Agent ID: [cyan]{result.agent_id}[/cyan]",
                title="[bold]ZIA Validation[/bold]",
                border_style="green",
            )
        )
    else:
        console.print(
            Panel(
                "\n".join(f"[red]• {e}[/red]" for e in result.errors),
                title=f"[bold red]❌ Validation Failed ({len(result.errors)} error(s))[/bold red]",
                border_style="red",
            )
        )
        sys.exit(1)


@cli.command()
@click.argument("path", type=click.Path(exists=True))
@click.option("--tenant", "-t", required=True, help="Tenant ID to run the agent under")
@click.option("--env", "-e", default="staging", show_default=True,
              help="Target environment (production, staging, dev)")
def run(path: str, tenant: str, env: str) -> None:
    """Run an agent defined by a YAML file under a tenant context."""
    from ulid import ULID
    from zia.core.runtime.agent import AgentContext
    from zia.core.runtime.executor import AgentExecutor
    from zia.tenants.context import TenantContext, TenantRegistry

    # Validate DSL first
    result = validate_agent(path)
    if not result.valid:
        console.print(f"[red]Cannot run: agent YAML is invalid.[/red]")
        for e in result.errors:
            console.print(f"  [red]• {e}[/red]")
        sys.exit(1)

    dsl = load_agent_yaml(path)
    trace_id = str(ULID())

    console.print(Panel(
        f"[bold]Agent:[/bold] {dsl.agent.name} ([cyan]{dsl.agent.id}[/cyan])\n"
        f"[bold]Tenant:[/bold] {tenant}\n"
        f"[bold]Environment:[/bold] {env}\n"
        f"[bold]Trace ID:[/bold] {trace_id}",
        title="[bold blue]🚀 ZIA Agent Run[/bold blue]",
        border_style="blue",
    ))

    # Set up executor
    registry = TenantRegistry()
    if not registry.exists(tenant):
        registry.register(tenant_id=tenant, name=tenant)

    context = AgentContext(
        tenant_id=tenant,
        trace_id=trace_id,
        dsl=dsl,
        environment=env,
    )

    # Trigger agent module imports so @register_agent decorators fire
    import zia.agents.risk_quant.agent  # noqa: F401
    import zia.agents.supply_chain.agent  # noqa: F401

    from zia.core.runtime.registry import AgentRegistry

    domain = dsl.agent.domain.value
    registry_instance = AgentRegistry.get()

    if not registry_instance.is_registered(domain):
        console.print(
            f"[yellow]⚠ No agent registered for domain '{domain}'.[/yellow]\n"
            f"  Implement a BaseAgent subclass and decorate it with "
            f"[cyan]@register_agent(domain=\"{domain}\")[/cyan]."
        )
        console.print(f"\nRegistered domains: {registry_instance.all_domains()}")
        sys.exit(0)

    agent_cls = registry_instance.resolve(domain)

    # Inject graph adapter for agents that need it (check constructor signature)
    import inspect
    sig = inspect.signature(agent_cls.__init__)
    if "adapter" in sig.parameters:
        from zia.sif.graph.adapter import KuzuAdapter
        adapter = KuzuAdapter()
        adapter.initialize_schema(tenant)
        agent = agent_cls(adapter)
    else:
        agent = agent_cls()


    executor = AgentExecutor()
    result_obj = executor.run(agent, context)

    if result_obj.success:
        console.print(f"\n[bold green]✅ Agent completed successfully[/bold green] "
                      f"in {result_obj.duration_ms:.1f}ms")
    else:
        console.print(f"\n[bold red]❌ Agent failed[/bold red]")
        for err in result_obj.errors:
            console.print(f"  [red]• {err}[/red]")
        sys.exit(1)


@cli.command()
def info() -> None:
    """Show ZIA platform info."""
    # Ensure agent modules are loaded so registry is populated
    import zia.agents.risk_quant.agent  # noqa: F401
    import zia.agents.supply_chain.agent  # noqa: F401
    from zia.core.runtime.registry import AgentRegistry

    reg = AgentRegistry.get()

    table = Table(title="ZIA Platform Info", border_style="blue")
    table.add_column("Property", style="bold cyan")
    table.add_column("Value")
    table.add_row("Version", zia.__version__)
    table.add_row("Author", zia.__author__)
    table.add_row("Registered Domains", ", ".join(reg.all_domains()) or "none")
    table.add_row("Graph Backend", "Kuzu (embedded) → Memgraph (production)")
    table.add_row("Multi-tenant", "✅ Namespace isolation")
    table.add_row("Audit", "✅ Structured JSON (structlog)")
    console.print(table)


@cli.command(name="agents")
def list_agents() -> None:
    """List all registered agent classes and their domains."""
    import zia.agents.risk_quant.agent  # noqa: F401
    import zia.agents.supply_chain.agent  # noqa: F401
    from zia.core.runtime.registry import AgentRegistry

    reg = AgentRegistry.get()
    regs = reg.all_registrations()

    if not regs:
        console.print("[yellow]No agents registered.[/yellow]")
        return

    table = Table(title="Registered Agents", border_style="cyan")
    table.add_column("Domain", style="bold cyan")
    table.add_column("Class")
    table.add_column("Version")
    table.add_column("Description")

    for r in regs:
        table.add_row(r.domain, r.class_name, r.version, r.description[:60])

    console.print(table)


@cli.command(name="serve")
@click.option("--host", default="0.0.0.0", show_default=True, help="Host to bind the API server to")
@click.option("--port", default=8000, show_default=True, help="Port to listen on")
@click.option("--reload", is_flag=True, default=False, help="Enable auto-reload (development only)")
def serve(host: str, port: int, reload: bool) -> None:
    """Start the ZIA REST API server."""
    console.print(Panel(
        f"[bold]Host:[/bold]  [cyan]{host}:{port}[/cyan]\n"
        f"[bold]Docs:[/bold]  [cyan]http://{host if host != '0.0.0.0' else 'localhost'}:{port}/docs[/cyan]\n"
        f"[bold]Reload:[/bold] {'[yellow]on[/yellow]' if reload else 'off'}",
        title="[bold blue]🚀 ZIA API Server[/bold blue]",
        border_style="blue",
    ))
    from zia.api.server import run
    run(host=host, port=port, reload=reload)


if __name__ == "__main__":
    cli()
