"""スケルトン生成モジュール（純粋関数）。

BUG-001: `railway sync transition` で通常ノードのスケルトンを生成。

設計方針:
- 純粋関数: 副作用なし、同じ入力に同じ出力
- イミュータブル: frozen dataclass
- 副作用の分離: IO操作は sync.py に委譲
"""
from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path


@dataclass(frozen=True)
class SkeletonSpec:
    """スケルトン生成の仕様（イミュータブル）。

    Note:
        dataclass を採用した理由:
        - 内部処理用でユーザーに直接公開されない
        - シリアライズ不要
        - SyncResult 等の既存内部型と一貫性がある
    """

    node_name: str
    module_path: str  # e.g., "nodes.myflow.new_node"
    entrypoint: str
    is_exit_node: bool


def generate_skeleton_spec(
    node_name: str,
    entrypoint: str,
    is_exit_node: bool,
) -> SkeletonSpec:
    """ノード名からスケルトン仕様を生成（純粋関数）。

    Args:
        node_name: ノード名（例: "check_time", "exit.success.done"）
        entrypoint: エントリーポイント名（例: "greeting"）
        is_exit_node: 終端ノードかどうか

    Returns:
        SkeletonSpec: スケルトン仕様

    Examples:
        >>> generate_skeleton_spec("check_time", "greeting", False)
        SkeletonSpec(node_name='check_time', module_path='nodes.greeting.check_time', ...)

        >>> generate_skeleton_spec("exit.success.done", "greeting", True)
        SkeletonSpec(node_name='exit.success.done', module_path='nodes.exit.success.done', ...)
    """
    if is_exit_node:
        # exit.success.done → nodes.exit.success.done
        module_path = f"nodes.{node_name}"
    else:
        # check_time → nodes.{entrypoint}.check_time
        module_path = f"nodes.{entrypoint}.{node_name}"

    return SkeletonSpec(
        node_name=node_name,
        module_path=module_path,
        entrypoint=entrypoint,
        is_exit_node=is_exit_node,
    )


def _to_pascal_case(name: str) -> str:
    """snake_case を PascalCase に変換（純粋関数）。

    Examples:
        >>> _to_pascal_case("check_time")
        'CheckTime'
        >>> _to_pascal_case("validate_user_input")
        'ValidateUserInput'
    """
    return "".join(word.capitalize() for word in name.split("_"))


def generate_regular_node_content(spec: SkeletonSpec) -> str:
    """通常ノードのスケルトンコードを生成（純粋関数）。

    Args:
        spec: スケルトン仕様

    Returns:
        生成された Python コード文字列

    Note:
        - 開始ノードとして使用可能なよう、ctx は Optional
        - run() 関数が initial_context を渡すため
    """
    func_name = spec.node_name.split(".")[-1]
    class_name = _to_pascal_case(func_name) + "Context"

    return f'''"""{func_name} ノード

Auto-generated by `railway sync transition`.
"""
from railway import Contract, node
from railway.core.dag import Outcome


class {class_name}(Contract):
    """{func_name} のコンテキスト。

    TODO: 必要なフィールドを定義してください。
    """

    pass


@node
def {func_name}(ctx: {class_name} | None = None) -> tuple[{class_name}, Outcome]:
    """{func_name} の処理を実行する。

    Args:
        ctx: 入力コンテキスト（開始ノードの場合は None 可）

    Returns:
        (更新されたコンテキスト, Outcome)

    TODO: 実装してください。
    """
    if ctx is None:
        ctx = {class_name}()

    return ctx, Outcome.success("done")
'''


def compute_file_path(spec: SkeletonSpec, src_dir: Path) -> Path:
    """スケルトンのファイルパスを計算（純粋関数）。

    Args:
        spec: スケルトン仕様
        src_dir: src ディレクトリ

    Returns:
        ファイルパス

    Examples:
        >>> compute_file_path(SkeletonSpec("check_time", ..., "greeting", False), Path("src"))
        Path("src/nodes/greeting/check_time.py")

        >>> compute_file_path(SkeletonSpec("exit.success.done", ..., "greeting", True), Path("src"))
        Path("src/nodes/exit/success/done.py")
    """
    if spec.is_exit_node:
        # exit.success.done → src/nodes/exit/success/done.py
        rel_path = Path("nodes") / spec.node_name.replace(".", "/")
    else:
        # check_time → src/nodes/{entrypoint}/check_time.py
        rel_path = Path("nodes") / spec.entrypoint / spec.node_name

    return src_dir / f"{rel_path}.py"


def filter_regular_nodes(yaml_nodes: tuple[str, ...]) -> tuple[str, ...]:
    """通常ノードのみをフィルタ（純粋関数）。

    終端ノード（exit.*）を除外する。

    Args:
        yaml_nodes: YAML で定義されている全ノード名

    Returns:
        通常ノード名のみのタプル
    """
    return tuple(name for name in yaml_nodes if not name.startswith("exit."))


def compute_skeleton_specs(
    node_names: tuple[str, ...],
    entrypoint: str,
) -> tuple[SkeletonSpec, ...]:
    """ノード名からスケルトン仕様を計算（純粋関数）。

    Args:
        node_names: 通常ノード名
        entrypoint: エントリーポイント名

    Returns:
        スケルトン仕様のタプル
    """
    return tuple(
        generate_skeleton_spec(name, entrypoint, is_exit_node=False)
        for name in node_names
    )
