"""Z8ter CLI scaffolding helpers.

This module provides simple code generators for pages and APIs using Jinja
templates. It renders files into your project's conventional directories
(`templates/pages`, `views`, `static/ts/pages`, `content`, and `api`).

Template resolution order (first match wins):
1) Local development overrides under `scaffold_dev/`
2) Built-in package templates under `z8ter/scaffold/`

Notes:
- Jinja delimiters are customized to avoid clashing with Jinja in Jinja
  (e.g., when generating `.jinja` files) and with TypeScript/HTML.

"""

from __future__ import annotations

from importlib.resources import as_file, files
from pathlib import Path

from jinja2 import (
    ChoiceLoader,
    Environment,
    FileSystemLoader,
    select_autoescape,
)

import z8ter


def _get_scaffold_path() -> str:
    """Get the path to the scaffold directory within the z8ter package."""
    scaffold_ref = files("z8ter").joinpath("scaffold")
    with as_file(scaffold_ref) as scaffold_path:
        return str(scaffold_path)


def _normalize_name(name: str) -> tuple[str, list[str]]:
    """Normalize a scaffold target into POSIX-like path segments."""
    normalized = name.strip().replace("\\", "/").strip("/")
    if not normalized:
        raise ValueError("Scaffold name cannot be empty.")

    parts = [part for part in normalized.split("/") if part]
    if not parts:
        raise ValueError("Scaffold name cannot be empty.")
    return normalized.lower(), [part.lower() for part in parts]


def _pascal_case(parts: list[str]) -> str:
    """Convert path segments into a Python class name."""
    joined = "_".join(parts)
    words = [word for word in joined.replace("-", "_").split("_") if word]
    return "".join(word[:1].upper() + word[1:] for word in words)


def _snake_case(parts: list[str]) -> str:
    """Convert path segments into a Python-safe method suffix."""
    return "_".join(part.replace("-", "_") for part in parts)


env = Environment(
    loader=ChoiceLoader(
        [
            FileSystemLoader("scaffold_dev"),
            FileSystemLoader(_get_scaffold_path()),
        ]
    ),
    autoescape=select_autoescape(
        enabled_extensions=(),
        default_for_string=False,
        default=False,
    ),
    variable_start_string="[[",
    variable_end_string="]]",
    block_start_string="[%",
    block_end_string="%]",
)


def create_page(page_name: str) -> None:
    """Scaffold a new SSR page (view, template, content, and TS island).

    Generates:
        - views/{name}.py                       (server-side view)
        - templates/pages/{name}.jinja          (Jinja template)
        - content/{name}.yaml                   (optional content stub)
        - static/ts/pages/{name}.ts             (client-side island)

    Args:
        page_name: Logical page identifier (e.g., "about", "app/home").

    Behavior:
        - Capitalizes `page_name` for class names (simple heuristic).
        - Creates parent directories as needed.
        - Overwrites existing files only if paths already exist and you allow it
          via your VCS workflow (no interactive prompts here).

    Raises:
        jinja2.TemplateNotFound: if a required template is missing.
        OSError: on filesystem write issues.

    """
    page_name_lower, parts = _normalize_name(page_name)
    class_name = _pascal_case(parts)
    relative_path = Path(*parts)

    template_path = z8ter.TEMPLATES_DIR / "pages" / relative_path.with_suffix(".jinja")
    view_path = z8ter.VIEWS_DIR / relative_path.with_suffix(".py")
    ts_path = z8ter.TS_DIR / "pages" / relative_path.with_suffix(".ts")
    content_path = z8ter.BASE_DIR / "content" / relative_path.with_suffix(".yaml")

    data = {
        "class_name": class_name,
        "page_name_lower": page_name_lower,
        "page_template_path": template_path.relative_to(z8ter.TEMPLATES_DIR).as_posix(),
    }

    files = [
        ("create_page_templates/view.py.j2", view_path),
        ("create_page_templates/page.jinja.j2", template_path),
        ("create_page_templates/page.yaml.j2", content_path),
        ("create_page_templates/page.ts.j2", ts_path),
    ]

    for tpl_name, out_path in files:
        tpl = env.get_template(tpl_name)
        text = tpl.render(**data)
        out_path.parent.mkdir(parents=True, exist_ok=True)
        out_path.write_text(text, encoding="utf-8")


def create_api(api_name: str) -> None:
    """Scaffold a new API class under `api/`.

    Generates:
        - api/{name}.py

    Args:
        api_name: Logical API identifier (e.g., "hello", "billing").

    Behavior:
        - Capitalizes `api_name` for a class name (simple heuristic).
        - Creates parent directories as needed.

    Raises:
        jinja2.TemplateNotFound: if the API template is missing.
        OSError: on filesystem write issues.

    """
    api_name_lower, parts = _normalize_name(api_name)
    class_name = _pascal_case(parts)
    method_name = f"get_{_snake_case(parts)}"
    api_path = z8ter.API_DIR / Path(*parts).with_suffix(".py")
    data = {
        "api_name_lower": api_name_lower.replace("/", "_"),
        "class_name": class_name,
        "method_name": method_name,
    }

    tpl = env.get_template("create_api_template/api.py.j2")
    text = tpl.render(**data)

    api_path.parent.mkdir(parents=True, exist_ok=True)
    api_path.write_text(text, encoding="utf-8")
