"""Implementation of the `strura gen:context` command."""

import re
from pathlib import Path

import typer

from strura.templates.gen_context_templates import (
    context_readme,
    erd_md,
    init_tables_py,
    schema_py,
)

# Regex for valid context names: lowercase snake_case
_VALID_NAME_RE = re.compile(r"^[a-z][a-z0-9_]*$")


def _to_pascal_case(name: str) -> str:
    """Convert snake_case name to PascalCase."""
    return "".join(word.capitalize() for word in name.split("_"))


def _validate_name(name: str) -> None:
    """Ensure the context name is valid snake_case."""
    if not _VALID_NAME_RE.match(name):
        typer.echo(
            f"Error: Invalid context name '{name}'. "
            "Use lowercase snake_case (e.g., 'my_context').",
            err=True,
        )
        raise typer.Exit(code=1)


def _validate_project_root(cwd: Path) -> None:
    """Ensure we are in a project root with pyproject.toml."""
    if not (cwd / "pyproject.toml").exists():
        typer.echo(
            "Error: No 'pyproject.toml' found. Run this command from your project root.",
            err=True,
        )
        raise typer.Exit(code=1)


def _validate_contexts_dir(contexts_dir: Path) -> None:
    """Ensure app/contexts/ directory exists."""
    if not contexts_dir.is_dir():
        typer.echo(
            "Error: Directory 'app/contexts/' not found. Run 'strura init' first.",
            err=True,
        )
        raise typer.Exit(code=1)


def _validate_not_exists(context_dir: Path, name: str) -> None:
    """Ensure the context doesn't already exist."""
    if context_dir.exists():
        typer.echo(
            f"Error: Context '{name}' already exists at {context_dir.relative_to(Path.cwd())}/.",
            err=True,
        )
        raise typer.Exit(code=1)


def gen_context(name: str) -> None:
    """Entry point for the gen:context command logic.

    Args:
        name: The context name in snake_case (e.g., 'person', 'security').
    """
    cwd = Path.cwd()
    pascal_name = _to_pascal_case(name)

    # Validations
    _validate_name(name)
    _validate_project_root(cwd)

    contexts_dir = cwd / "app" / "contexts"
    _validate_contexts_dir(contexts_dir)

    context_dir = contexts_dir / name
    _validate_not_exists(context_dir, name)

    typer.echo(f"\nCreating bounded context: {name}\n")
    typer.echo("Generating context structure...\n")

    # Directories to create
    directories: list[str] = [
        "",
        "application",
        "domain",
        "domain/enum",
        "domain/schemas",
        "infrastructure",
        "infrastructure/database",
        "infrastructure/database/models",
        "docs",
        "docs/entities",
    ]

    for directory in directories:
        dir_path = context_dir / directory
        dir_path.mkdir(parents=True, exist_ok=True)

    # Files to generate: (relative_path, content)
    files: list[tuple[str, str]] = [
        ("__init__.py", ""),
        ("README.md", context_readme(name, pascal_name)),
        ("application/__init__.py", ""),
        ("domain/__init__.py", ""),
        ("domain/enum/__init__.py", ""),
        ("domain/schemas/__init__.py", ""),
        ("infrastructure/__init__.py", ""),
        ("infrastructure/database/__init__.py", ""),
        ("infrastructure/database/schema.py", schema_py(name)),
        ("infrastructure/database/init_tables.py", init_tables_py(name)),
        ("infrastructure/database/models/__init__.py", ""),
        ("infrastructure/database/models/ERD.md", erd_md(pascal_name)),
    ]

    created_count = 0
    for relative_path, content in files:
        file_path = context_dir / relative_path
        file_path.write_text(content, encoding="utf-8")
        created_count += 1
        typer.echo(f"  Created: app/contexts/{name}/{relative_path}")

    typer.echo(f"\nSummary: {created_count} files created.")
    typer.echo(f"\nContext '{name}' is ready at app/contexts/{name}/")
