from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path


def _repo_root(module_file: Path) -> Path:
    return module_file.resolve().parents[2]


def _common_repo_root(repo_root: Path) -> Path:
    git_path = repo_root / ".git"
    if git_path.is_dir():
        return repo_root
    if not git_path.is_file():
        return repo_root

    contents = git_path.read_text(encoding="utf-8").strip()
    prefix = "gitdir:"
    if not contents.startswith(prefix):
        return repo_root

    gitdir = contents[len(prefix) :].strip()
    common_git_dir = (repo_root / gitdir).resolve()
    if common_git_dir.name == ".git":
        return common_git_dir.parent
    if common_git_dir.parent.name == "worktrees" and common_git_dir.parent.parent.name == ".git":
        return common_git_dir.parents[2]
    return repo_root


@dataclass(frozen=True)
class RenderedConsumerCommand:
    label: str
    argv: tuple[str, ...]
    env: dict[str, str]


@dataclass(frozen=True)
class ConsumerCommandTemplate:
    label: str
    argv_template: tuple[str, ...]

    def render(self, *, preset_path: Path, unuforge_repo_root: Path) -> RenderedConsumerCommand:
        substitutions = {
            "{preset}": str(preset_path),
        }
        argv = tuple(substitutions.get(item, item) for item in self.argv_template)
        return RenderedConsumerCommand(
            label=self.label,
            argv=argv,
            env={"UNUFORGE_REPO_ROOT": str(unuforge_repo_root)},
        )


@dataclass(frozen=True)
class OfficialConsumerContract:
    code: str
    repo_dir_name: str
    preset_relpath: Path
    commands: tuple[ConsumerCommandTemplate, ...]

    def render_commands(
        self,
        *,
        consumer_repo_root: Path,
        unuforge_repo_root: Path,
    ) -> list[RenderedConsumerCommand]:
        preset_path = consumer_repo_root / self.preset_relpath
        return [
            command.render(preset_path=preset_path, unuforge_repo_root=unuforge_repo_root)
            for command in self.commands
        ]


def current_unuforge_repo_root() -> Path:
    return _repo_root(Path(__file__))


def default_consumer_repo_root(
    consumer: OfficialConsumerContract,
    *,
    unuforge_repo_root: Path | None = None,
) -> Path:
    repo_root = current_unuforge_repo_root() if unuforge_repo_root is None else unuforge_repo_root
    common_repo_root = _common_repo_root(repo_root.resolve())
    return common_repo_root.parent / consumer.repo_dir_name


OFFICIAL_CONSUMERS: dict[str, OfficialConsumerContract] = {
    "unudispatch": OfficialConsumerContract(
        code="unudispatch",
        repo_dir_name="unudispatch",
        preset_relpath=Path("presets/unudispatch/release-preset.json"),
        commands=(
            ConsumerCommandTemplate(
                label="preset-inspect",
                argv_template=(
                    "python3",
                    "-m",
                    "unuforge.cli",
                    "preset",
                    "inspect",
                    "--preset",
                    "{preset}",
                    "--json",
                ),
            ),
            ConsumerCommandTemplate(
                label="profiles-list",
                argv_template=(
                    "python3",
                    "-m",
                    "unuforge.cli",
                    "profiles",
                    "list",
                    "--preset",
                    "{preset}",
                    "--json",
                ),
            ),
            ConsumerCommandTemplate(
                label="profiles-run-lint-runner-dry-run",
                argv_template=(
                    "python3",
                    "-m",
                    "unuforge.cli",
                    "profiles",
                    "run",
                    "lint-runner",
                    "--preset",
                    "{preset}",
                    "--host-adapter",
                    "unudispatch_forge_host",
                    "--dry-run",
                    "--json",
                ),
            ),
            ConsumerCommandTemplate(
                label="profiles-run-test-runner-dry-run",
                argv_template=(
                    "python3",
                    "-m",
                    "unuforge.cli",
                    "profiles",
                    "run",
                    "test-runner",
                    "--preset",
                    "{preset}",
                    "--host-adapter",
                    "unudispatch_forge_host",
                    "--dry-run",
                    "--json",
                ),
            ),
        ),
    ),
    "unuidentity": OfficialConsumerContract(
        code="unuidentity",
        repo_dir_name="unuidentity",
        preset_relpath=Path("presets/unuidentity/phase0-bootstrap-preset.json"),
        commands=(
            ConsumerCommandTemplate(
                label="preset-inspect",
                argv_template=(
                    "python3",
                    "-m",
                    "unuforge.cli",
                    "preset",
                    "inspect",
                    "--preset",
                    "{preset}",
                    "--json",
                ),
            ),
            ConsumerCommandTemplate(
                label="profiles-list",
                argv_template=(
                    "python3",
                    "-m",
                    "unuforge.cli",
                    "profiles",
                    "list",
                    "--preset",
                    "{preset}",
                    "--json",
                ),
            ),
            ConsumerCommandTemplate(
                label="profiles-run-identity-env-template-dry-run",
                argv_template=(
                    "python3",
                    "-m",
                    "unuforge.cli",
                    "profiles",
                    "run",
                    "identity.env-template",
                    "--preset",
                    "{preset}",
                    "--host-adapter",
                    "unuidentity_forge_host",
                    "--dry-run",
                    "--json",
                ),
            ),
            ConsumerCommandTemplate(
                label="actions-run-identity-bootstrap-apply-dry-run",
                argv_template=(
                    "python3",
                    "-m",
                    "unuforge.cli",
                    "actions",
                    "run",
                    "identity.bootstrap.apply",
                    "--preset",
                    "{preset}",
                    "--host-adapter",
                    "unuidentity_forge_host",
                    "--dry-run",
                    "--json",
                    "--",
                    "--dry-run",
                ),
            ),
            ConsumerCommandTemplate(
                label="actions-run-identity-bootstrap-check-dry-run",
                argv_template=(
                    "python3",
                    "-m",
                    "unuforge.cli",
                    "actions",
                    "run",
                    "identity.bootstrap.check",
                    "--preset",
                    "{preset}",
                    "--host-adapter",
                    "unuidentity_forge_host",
                    "--dry-run",
                    "--json",
                    "--",
                    "--dry-run",
                ),
            ),
        ),
    ),
    "unuvault": OfficialConsumerContract(
        code="unuvault",
        repo_dir_name="unuvault",
        preset_relpath=Path("presets/unuvault/release-preset.json"),
        commands=(
            ConsumerCommandTemplate(
                label="preset-inspect",
                argv_template=(
                    "python3",
                    "-m",
                    "unuforge.cli",
                    "preset",
                    "inspect",
                    "--preset",
                    "{preset}",
                    "--json",
                ),
            ),
            ConsumerCommandTemplate(
                label="profiles-list",
                argv_template=(
                    "python3",
                    "-m",
                    "unuforge.cli",
                    "profiles",
                    "list",
                    "--preset",
                    "{preset}",
                    "--json",
                ),
            ),
            ConsumerCommandTemplate(
                label="profiles-run-lint-runner-dry-run",
                argv_template=(
                    "python3",
                    "-m",
                    "unuforge.cli",
                    "profiles",
                    "run",
                    "lint-runner",
                    "--preset",
                    "{preset}",
                    "--host-adapter",
                    "unuvault_forge_host",
                    "--dry-run",
                    "--json",
                ),
            ),
            ConsumerCommandTemplate(
                label="profiles-run-test-runner-dry-run",
                argv_template=(
                    "python3",
                    "-m",
                    "unuforge.cli",
                    "profiles",
                    "run",
                    "test-runner",
                    "--preset",
                    "{preset}",
                    "--host-adapter",
                    "unuvault_forge_host",
                    "--dry-run",
                    "--json",
                ),
            ),
        ),
    ),
}
