from __future__ import annotations

import os
import subprocess
from collections import OrderedDict
from dataclasses import dataclass
from pathlib import Path
from typing import Mapping, Optional, Sequence

from .runtime import data_root_from_env, ensure_runtime

DEFAULT_DATA_ROOT = "/root/data"
DEFAULT_LEHOME_REPO_URL = "https://github.com/sudo-yf/lehome-challenge.git"
DEFAULT_SOURCE_ROOT = "/root/data/lehome_cli"


@dataclass(frozen=True)
class CommandSpec:
    name: str
    script_relpath: str
    description: str
    cwd_mode: str = "data_root"


COMMANDS: "OrderedDict[str, CommandSpec]" = OrderedDict(
    [
        (
            "all",
            CommandSpec(
                name="all",
                script_relpath="all.sh",
                description="运行原版 all.sh",
                cwd_mode="preserve",
            ),
        ),
        ("step1", CommandSpec("step1", "v1/step1.sh", "运行 v1/step1.sh")),
        ("step2", CommandSpec("step2", "v1/step2.sh", "运行 v1/step2.sh")),
        ("step3", CommandSpec("step3", "v1/step3.sh", "运行 v1/step3.sh")),
        ("ai", CommandSpec("ai", "v1/step_ai.sh", "运行 v1/step_ai.sh")),
        ("git", CommandSpec("git", "v1/step_git.sh", "运行 v1/step_git.sh")),
        ("diff", CommandSpec("diff", "v1/step_diff.sh", "运行 v1/step_diff.sh")),
        ("vpn", CommandSpec("vpn", "v1/step_vpn.sh", "运行 v1/step_vpn.sh")),
    ]
)


def build_env(base_env: Optional[Mapping[str, str]] = None) -> dict[str, str]:
    env = dict(base_env or os.environ)
    env.setdefault("DATA_ROOT", DEFAULT_DATA_ROOT)
    env.setdefault("LEHOME_REPO_URL", DEFAULT_LEHOME_REPO_URL)
    env.setdefault("LEHOME_CLI_SOURCE", DEFAULT_SOURCE_ROOT)
    return env


def resolve_script_path(command_name: str, runtime_dir: Path) -> Path:
    spec = COMMANDS[command_name]
    return runtime_dir / spec.script_relpath


def resolve_workdir(command_name: str, env: Mapping[str, str]) -> Path:
    spec = COMMANDS[command_name]
    if spec.cwd_mode == "preserve":
        return Path.cwd()

    data_root = data_root_from_env(env)
    data_root.mkdir(parents=True, exist_ok=True)
    return data_root


def run_named_command(command_name: str, args: Sequence[str]) -> int:
    if command_name not in COMMANDS:
        raise KeyError(f"unsupported command: {command_name}")

    env = build_env()
    runtime_dir = ensure_runtime(env)
    script_path = resolve_script_path(command_name, runtime_dir)
    workdir = resolve_workdir(command_name, env)

    if not script_path.is_file():
        raise FileNotFoundError(f"runtime script not found: {script_path}")

    completed = subprocess.run(
        ["bash", str(script_path), *args],
        cwd=str(workdir),
        env=env,
        check=False,
    )
    return int(completed.returncode)
