"""
Init command for EvenAge CLI.

Creates new EvenAge projects with full scaffolding.
"""

from __future__ import annotations

from pathlib import Path

import click
from rich.progress import Progress, SpinnerColumn, TextColumn
import yaml

from ..utils import (
    NestedProjectError,
    ProjectConfigSchema,
    ProjectDetails,
    ProjectExistsError,
    add_worker_to_compose,
    get_template_renderer,
    print_panel,
    print_success,
    validate_project_directory,
    write_file,
)


@click.command()
@click.argument("project_name", required=False)
@click.option("--path", default=".", help="Path to create project in")
def init(project_name: str | None, path: str):
    """Initialize a new EvenAge project.
    
    Creates project structure with:
    - Configuration files (evenage.yml, .env)
    - Docker setup (docker-compose.yml, Dockerfile)
    - Default researcher agent
    - Example tools and pipeline
    
    Users import from evenage package:
        from evenage import Agent, AgentRunner, run_agent, actor, tool
    
    Examples:
        evenage init myproject
        evenage init myproject --path /path/to/dir
        evenage init  # Interactive mode
    """
    # Prompt for project name if not provided
    if not project_name:
        project_name = click.prompt("Project name")

    # Resolve project path
    project_path = Path(path)
    if project_name and project_name != ".":
        project_path = project_path / project_name
    project_path = project_path.resolve()

    # Check if project already exists
    if project_path.exists() and validate_project_directory(project_path):
        raise ProjectExistsError(str(project_path))

    # Check for nested project
    for parent in project_path.parents:
        if validate_project_directory(parent):
            raise NestedProjectError(str(parent))

    # Handle in-place creation
    create_in_place = False
    if project_name in (".", ""):
        create_in_place = True
    else:
        cwd_name = Path.cwd().name
        if path in (".", "") and project_name == cwd_name:
            create_in_place = True

    if create_in_place:
        project_path = Path.cwd().resolve()

    # Check if directory is empty (except for existing evenage.yml)
    if project_path.exists() and any(project_path.iterdir()):
        if not validate_project_directory(project_path):
            raise ProjectExistsError(str(project_path))

    print_panel(
        "Initializing EvenAge Project",
        f"Creating project: [bold]{project_path.name}[/bold]",
    )

    # Interactive infra choices
    click.echo("")
    enable_scaling = click.confirm("Do you want to scale your application for large workloads?", default=True)
    queue_choice = "inmemory"
    db_choice = "local"
    storage_choice = "local"
    if enable_scaling:
        if click.confirm("Do you want to use a queueing system for distributed tasks? (Redis)", default=True):
            queue_choice = "redis"
        else:
            queue_choice = "inmemory"
        if click.confirm("Do you want to store traces and agent states in a database? (PostgreSQL)", default=True):
            db_choice = "postgres"
        else:
            db_choice = "local"  # will map to sqlite
        if click.confirm("Do you want to store large files or artifacts (MinIO)", default=True):
            storage_choice = "minio"
        else:
            storage_choice = "local"

    with Progress(
        SpinnerColumn(),
        TextColumn("[progress.description]{task.description}"),
    ) as progress:
        task = progress.add_task("Creating project structure...", total=None)

        # Create directory structure
        _create_directories(project_path)

        # Generate core modules
        progress.update(task, description="Generating core modules...")
        _generate_core_modules(project_path)

        # Generate configuration files
        progress.update(task, description="Creating configuration...")
        _generate_config_files(project_path, project_path.name, enable_scaling, queue_choice, db_choice, storage_choice)

        # Generate Docker setup
        progress.update(task, description="Creating Docker configuration...")
        _generate_docker_setup(project_path)

        # Generate default agent
        progress.update(task, description="Seeding default agent...")
        _generate_default_agent(project_path)

        # Generate README
        progress.update(task, description="Creating README...")
        _generate_readme(project_path, project_path.name)

    print_success(f"Project created: {project_path}")
    print_panel(
        "Next Steps",
        f"cd {project_path if project_path != Path.cwd() else '.'}\nevenage run dev",
        style="green",
    )


def _create_directories(project_path: Path) -> None:
    """Create project directory structure."""
    directories = [
        project_path,
        project_path / "agents",
        project_path / "workers",
        project_path / "pipelines",
    ]

    for directory in directories:
        directory.mkdir(parents=True, exist_ok=True)
    
    # Make workers a Python package so `python -m workers.X_worker` works
    write_file(project_path / "workers" / "__init__.py", "")


def _generate_core_modules(project_path: Path) -> None:
    """
    V3.0: Users import from evenage package, no need to generate core files.
    
    This function is kept for backward compatibility but does nothing.
    Users should use: from evenage import Agent, AgentRunner, run_agent
    """


def _generate_config_files(project_path: Path, project_name: str, enable_scaling: bool, queue_choice: str, db_choice: str, storage_choice: str) -> None:
    """Generate configuration files."""
    renderer = get_template_renderer()

    # evenage.yml (legacy project config for scaffolding)
    config = ProjectConfigSchema(
        project=ProjectDetails(
            name=project_name,
            broker="redis",
            database="postgres",
            storage="minio",
            tracing=True,
            metrics=True,
            agents=[],
        )
    )
    config.save_to_file(project_path / "evenage.yml")

    # .env
    renderer.render_to_file("dotenv.j2", project_path / ".env", {})

    # .evenage/config.json (runtime backend config)
    from json import dumps
    runtime_cfg = {
        "enable_scaling": bool(enable_scaling),
        "queue_backend": queue_choice if enable_scaling else "inmemory",
        "db_backend": db_choice if enable_scaling else "local",
        "storage_backend": storage_choice if enable_scaling else "local",
    }
    cfg_dir = project_path / ".evenage"
    cfg_dir.mkdir(parents=True, exist_ok=True)
    (cfg_dir / "config.json").write_text(dumps(runtime_cfg, indent=2), encoding="utf-8")


def _generate_docker_setup(project_path: Path) -> None:
    """Generate Docker configuration."""
    renderer = get_template_renderer()

    renderer.render_to_file("docker-compose.yml.j2", project_path / "docker-compose.yml", {})
    renderer.render_to_file("Dockerfile.j2", project_path / "Dockerfile", {})
    renderer.render_to_file("requirements.txt.j2", project_path / "requirements.txt", {})


def _generate_default_agent(project_path: Path) -> None:
    """Generate default coordinator and researcher agents."""
    renderer = get_template_renderer()

    # Create agents directory __init__
    write_file(project_path / "agents" / "__init__.py", "")

    # Define both default agents
    default_agents = [
        {
            "name": "coordinator",
            "role": "Coordinator Agent",
            "goal": "Orchestrate multi-agent workflows and delegate tasks to specialist agents.",
            "backstory": "An experienced coordinator that analyzes tasks, delegates to specialists, and synthesizes results.",
            "template": "agent_coordinator.py.j2",
            "tools": [],
            "allow_delegation": True,
        },
        {
            "name": "researcher",
            "role": "Research Agent",
            "goal": "Research topics on the web and summarize findings concisely.",
            "backstory": "A helpful researcher that gathers and condenses information from reliable web sources.",
            "template": "agent_handler.py.j2",
            "tools": ["web_search"],
            "allow_delegation": False,
        }
    ]

    agent_names = []

    for agent_config in default_agents:
        agent_name = agent_config["name"]
        agent_names.append(agent_name)

        # Agent directory structure
        agent_path = project_path / "agents" / agent_name
        agent_path.mkdir(parents=True, exist_ok=True)
        write_file(agent_path / "__init__.py", "")

        # Create tools directory if agent has tools
        if agent_config["tools"]:
            tools_path = agent_path / "tools"
            tools_path.mkdir(parents=True, exist_ok=True)
            write_file(tools_path / "__init__.py", "")

            # Generate web search tool for researcher
            if "web_search" in agent_config["tools"]:
                renderer.render_to_file("tool_web_search.py.j2", tools_path / "web_search.py", {})

        # Agent handler (use coordinator template for coordinator, standard handler for others)
        handler_context = {
            "agent_name": agent_name,
            "role": agent_config["role"],
            "goal": agent_config["goal"],
            "backstory": agent_config["backstory"],
            "allow_delegation": agent_config["allow_delegation"],
            "max_iterations": 15,
            "description": f"Default {agent_name} agent.",
            "tools": agent_config["tools"],
        }
        renderer.render_to_file(agent_config["template"], agent_path / "handler.py", handler_context)

        # Agent prompt policy (user-visible system prompt supplement)
        renderer.render_to_file(
            "prompt.md.j2",
            agent_path / "prompt.md",
            {
                "agent_name": agent_name,
                "role": agent_config["role"],
                "goal": agent_config["goal"],
                "backstory": agent_config["backstory"],
            },
        )

        # Worker
        worker_context = {
            "agent_name": agent_name,
            "role": agent_config["role"],
            "goal": agent_config["goal"],
        }
        renderer.render_to_file(
            "agent_worker.py.j2",
            project_path / "workers" / f"{agent_name}_worker.py",
            worker_context,
        )

        # Add worker service to docker-compose.yml
        add_worker_to_compose(project_path, agent_name)

    # Main entrypoint - routes to coordinator by default
    renderer.render_to_file(
        "main_agent_entry.py.j2",
        project_path / "main.py",
        {"default_agent": "coordinator"},
    )

    # Update evenage.yml to add both agents
    config_path = project_path / "evenage.yml"
    with open(config_path, "r", encoding="utf-8") as f:
        config_data = yaml.safe_load(f)

    config_data["project"]["agents"] = agent_names

    with open(config_path, "w", encoding="utf-8") as f:
        yaml.dump(config_data, f, default_flow_style=False, sort_keys=False)

    # Create example pipeline
    pipeline_context = {
        "pipeline_name": "research_pipeline",
        "description": "Example research pipeline using the researcher agent",
    }
    renderer.render_to_file(
        "pipeline.yml.j2",
        project_path / "pipelines" / "research_pipeline.yml",
        pipeline_context,
    )


def _generate_readme(project_path: Path, project_name: str) -> None:
    """Generate project README."""
    renderer = get_template_renderer()
    renderer.render_to_file(
        "README.md.j2",
        project_path / "README.md",
        {"project_name": project_name},
    )
