"""
CLI for iq-sdk.

Commands:
- init: Initialize a new project
- site: Manage sites (add, list, drop)
- tool: Manage tools (create, list, register, unregister)
- worker: Manage workers (create, list, start)
- config: Manage configuration
"""

from __future__ import annotations

import shutil
import sys
from pathlib import Path

import click
import yaml
from rich.console import Console

from iq_sdk import __version__

console = Console()

# Template directory location
TEMPLATES_DIR = Path(__file__).parent.parent / "templates"


def get_template_path(template_name: str) -> Path:
    """Get path to a template directory or file."""
    return TEMPLATES_DIR / template_name


def render_template(template_path: Path, output_path: Path, context: dict) -> None:
    """Render a Jinja2 template file."""
    from jinja2 import Template

    content = template_path.read_text()
    template = Template(content)
    rendered = template.render(**context)

    output_path.parent.mkdir(parents=True, exist_ok=True)
    output_path.write_text(rendered)


def copy_template_dir(template_name: str, dest: Path, context: dict) -> None:
    """Copy and render a template directory."""
    template_dir = get_template_path(template_name)

    if not template_dir.exists():
        console.print(f"[red]Template '{template_name}' not found[/red]")
        sys.exit(1)

    for src_file in template_dir.rglob("*"):
        if src_file.is_file():
            rel_path = src_file.relative_to(template_dir)
            dest_rel = str(rel_path).replace("__name__", context.get("name", ""))
            dest_file = dest / dest_rel

            if src_file.suffix in (".py", ".yml", ".yaml", ".md", ".json", ".toml", ".j2"):
                # Remove .j2 extension from output
                if dest_file.suffix == ".j2":
                    dest_file = dest_file.with_suffix("")
                render_template(src_file, dest_file, context)
            else:
                dest_file.parent.mkdir(parents=True, exist_ok=True)
                shutil.copy2(src_file, dest_file)


def load_config_file(config_path: Path) -> dict:
    """Load YAML config file."""
    if config_path.exists():
        with open(config_path) as f:
            return yaml.safe_load(f) or {}
    return {}


def save_config_file(config_path: Path, data: dict) -> None:
    """Save YAML config file."""
    config_path.parent.mkdir(parents=True, exist_ok=True)
    with open(config_path, "w") as f:
        yaml.dump(data, f, default_flow_style=False, sort_keys=False)


# ============================================================================
# PROJECT DETECTION
# ============================================================================


def resolve_config_name(name: str | None) -> str | None:
    """
    Resolve config name to full path.

    Examples:
        None → None (uses default config/settings.yml)
        "production" → "config/production.yml"
        "settings" → "config/settings.yml"
        "config/custom.yml" → "config/custom.yml" (already a path)
    """
    if name is None:
        return None

    # If it looks like a path (contains / or ends with .yml), use as-is
    if "/" in name or name.endswith(".yml") or name.endswith(".yaml"):
        return name

    # Otherwise, treat as config name and resolve to config/{name}.yml
    return f"config/{name}.yml"


def get_project_dir_for_cli(require: bool = True) -> Path | None:
    """
    Get project directory for CLI commands.

    This is called at CLI startup to determine the working directory.
    If IQ_PROJECT_DIR is set, use that. Otherwise search from cwd.

    Args:
        require: If True, raise error when no project found

    Returns:
        Project directory path, or None if not required and not found
    """
    from iq_sdk.cli.project import find_project_root

    project = find_project_root()

    if project is None and require:
        # For some commands (init, use), we don't require a project
        return None

    return project


def require_project(ctx: click.Context) -> Path:
    """
    Require a valid project directory for CLI commands.

    Call this at the start of commands that need a project.
    Raises click.ClickException if no valid project found.

    Args:
        ctx: Click context

    Returns:
        Path to the project directory
    """
    from iq_sdk.cli.project import find_project_root, is_valid_project

    # Check if we already validated
    if ctx.obj and ctx.obj.get("_project_validated"):
        return ctx.obj["project_dir"]

    project = find_project_root()

    if project is None or not is_valid_project(project):
        raise click.ClickException(
            "Not in a valid iq-sdk project directory.\n"
            "Run 'iq init' to create a project, or 'iq use <project>' to activate one."
        )

    # Cache the result
    if ctx.obj:
        ctx.obj["project_dir"] = project
        ctx.obj["_project_validated"] = True

    return project


# ============================================================================
# MAIN CLI GROUP
# ============================================================================

CONTEXT_SETTINGS = {"help_option_names": ["-h", "--help"]}


@click.group(context_settings=CONTEXT_SETTINGS)
@click.version_option(version=__version__, prog_name="iq-sdk")
@click.option(
    "--config",
    "-c",
    type=str,
    envvar="IQ_CONFIG",
    help="Config name (e.g. 'production' → config/production.yml)",
)
@click.option(
    "--site",
    "-s",
    type=str,
    envvar="IQ_SITE",
    help="Site ID to use (default: 'default')",
)
@click.pass_context
def cli(ctx: click.Context, config: str | None, site: str | None) -> None:
    """iq-sdk - SDK for distributed workers and tools."""
    # Load .env from active project (only sets unset variables)
    from iq_sdk.cli.project import load_project_dotenv

    load_project_dotenv()

    ctx.ensure_object(dict)
    ctx.obj["config_file"] = resolve_config_name(config)
    ctx.obj["site_id"] = site

    # Find project directory (don't require for init/use commands)
    # This is used by other commands to resolve paths
    project_dir = get_project_dir_for_cli(require=False)
    ctx.obj["project_dir"] = project_dir


# Import and register subcommands
from iq_sdk.cli.config import config as config_cmd
from iq_sdk.cli.devcontainer import devcontainer
from iq_sdk.cli.init import init
from iq_sdk.cli.project import project_info, use
from iq_sdk.cli.site import site
from iq_sdk.cli.tool import tool
from iq_sdk.cli.worker import worker

cli.add_command(init)
cli.add_command(site)
cli.add_command(tool)
cli.add_command(worker)
cli.add_command(config_cmd)
cli.add_command(devcontainer)
cli.add_command(use)
cli.add_command(project_info, name="project")


def main() -> None:
    """Entry point for CLI."""
    cli()


if __name__ == "__main__":
    main()
