from __future__ import annotations

import importlib.util
import os
from pathlib import Path
import sys
from types import ModuleType
from types import SimpleNamespace
import tempfile
import unittest


ROOT = Path(__file__).resolve().parents[1]
SCRIPT = ROOT / "scripts" / "verify_installed_package_consumers.py"


def _load_script_module() -> ModuleType:
    spec = importlib.util.spec_from_file_location("verify_installed_package_consumers", SCRIPT)
    if spec is None or spec.loader is None:
        raise RuntimeError(f"Unable to load module from {SCRIPT}")
    module = importlib.util.module_from_spec(spec)
    sys.modules[spec.name] = module
    spec.loader.exec_module(module)
    return module


class InstalledPackageConsumerTests(unittest.TestCase):
    def test_initial_installed_package_gate_matches_current_smokes(self) -> None:
        module = _load_script_module()

        self.assertEqual(set(module.INSTALLED_PACKAGE_CONSUMERS), {"unuidentity", "unundo"})

        unuidentity = module.INSTALLED_PACKAGE_CONSUMERS["unuidentity"]
        self.assertEqual(unuidentity.code, "unuidentity")
        self.assertEqual(unuidentity.repo_dir_name, "unuidentity")
        self.assertEqual(
            unuidentity.smoke_relpath,
            Path("scripts/ci/tests/test_unuforge_phase0_consumer_smoke.py"),
        )

        unundo = module.INSTALLED_PACKAGE_CONSUMERS["unundo"]
        self.assertEqual(unundo.code, "unundo")
        self.assertEqual(unundo.repo_dir_name, "unundo")
        self.assertEqual(
            unundo.smoke_relpath,
            Path("scripts/ci/tests/test_unuforge_package_consumer_smoke.py"),
        )

    def test_script_can_select_all_or_one_consumer(self) -> None:
        module = _load_script_module()

        self.assertEqual(
            [consumer.code for consumer in module.resolve_selected_consumers("all")],
            ["unuidentity", "unundo"],
        )
        self.assertEqual(
            [consumer.code for consumer in module.resolve_selected_consumers("unundo")],
            ["unundo"],
        )

        with self.assertRaisesRegex(ValueError, "Unknown consumer"):
            module.resolve_selected_consumers("unuvault")

    def test_resolve_consumer_repo_root_uses_parent_of_standard_checkout(self) -> None:
        module = _load_script_module()

        with tempfile.TemporaryDirectory() as tmp_dir:
            temp_root = Path(tmp_dir)
            repo_root = temp_root / "portfolio" / "unuforge"
            (repo_root / ".git").mkdir(parents=True)

            resolved = module.resolve_consumer_repo_root(
                module.INSTALLED_PACKAGE_CONSUMERS["unuidentity"],
                unuforge_repo_root=repo_root,
            )

        self.assertEqual(resolved, (temp_root / "portfolio" / "unuidentity").resolve())

    def test_resolve_consumer_repo_root_uses_common_checkout_parent_for_worktree(self) -> None:
        module = _load_script_module()

        with tempfile.TemporaryDirectory() as tmp_dir:
            temp_root = Path(tmp_dir)
            common_repo_root = temp_root / "portfolio" / "unuforge"
            common_git_dir = common_repo_root / ".git" / "worktrees" / "unuforge-feature"
            worktree_root = temp_root / "worktrees" / "unuforge-feature"

            common_git_dir.mkdir(parents=True)
            worktree_root.mkdir(parents=True)
            (worktree_root / ".git").write_text(
                f"gitdir: {common_git_dir}\n",
                encoding="utf-8",
            )

            resolved = module.resolve_consumer_repo_root(
                module.INSTALLED_PACKAGE_CONSUMERS["unundo"],
                unuforge_repo_root=worktree_root,
            )

        self.assertEqual(resolved, (temp_root / "portfolio" / "unundo").resolve())

    def test_resolve_consumer_repo_root_honors_explicit_env_override(self) -> None:
        module = _load_script_module()

        resolved = module.resolve_consumer_repo_root(
            module.INSTALLED_PACKAGE_CONSUMERS["unundo"],
            env={"UNUNDO_REPO_ROOT": "/tmp/override-unundo"},
            unuforge_repo_root=Path("/tmp/unuforge"),
        )

        self.assertEqual(resolved, Path("/tmp/override-unundo"))

    def test_rendered_command_uses_wheel_env_and_downstream_smoke_script(self) -> None:
        module = _load_script_module()

        rendered = module.INSTALLED_PACKAGE_CONSUMERS["unuidentity"].render_command(
            consumer_repo_root=Path("/tmp/unuidentity"),
            wheel_path=Path("/tmp/dist/unuforge-0.1.0-py3-none-any.whl"),
        )

        self.assertEqual(rendered.label, "installed-package-smoke")
        self.assertEqual(
            rendered.argv,
            (
                "python3",
                "/tmp/unuidentity/scripts/ci/tests/test_unuforge_phase0_consumer_smoke.py",
            ),
        )
        self.assertEqual(
            rendered.env,
            {"UNUFORGE_WHEEL_PATH": "/tmp/dist/unuforge-0.1.0-py3-none-any.whl"},
        )

    def test_format_missing_repo_message_with_override_hint(self) -> None:
        module = _load_script_module()

        message = module.format_missing_repo_message(
            module.INSTALLED_PACKAGE_CONSUMERS["unuidentity"],
            Path("/tmp/missing-unuidentity"),
        )

        self.assertIn("Missing consumer checkout for unuidentity", message)
        self.assertIn("UNUIDENTITY_REPO_ROOT=/absolute/path/to/unuidentity", message)

    def test_run_installed_package_consumer_calls_expected_command(self) -> None:
        module = _load_script_module()
        recorded: list[SimpleNamespace] = []

        def fake_runner(argv: tuple[str, ...], *, cwd: Path, env: dict[str, str]) -> SimpleNamespace:
            recorded.append(SimpleNamespace(argv=argv, cwd=cwd, env=env))
            return SimpleNamespace(returncode=0, stdout="", stderr="")

        module.run_installed_package_consumer(
            module.INSTALLED_PACKAGE_CONSUMERS["unundo"],
            consumer_repo_root=Path("/tmp/unundo"),
            wheel_path=Path("/tmp/dist/unuforge-0.1.0-py3-none-any.whl"),
            runner=fake_runner,
        )

        self.assertEqual(len(recorded), 1)
        self.assertEqual(
            recorded[0].argv,
            (
                "python3",
                "/tmp/unundo/scripts/ci/tests/test_unuforge_package_consumer_smoke.py",
            ),
        )
        self.assertEqual(recorded[0].cwd, Path("/tmp/unundo"))
        self.assertEqual(
            recorded[0].env,
            {"UNUFORGE_WHEEL_PATH": "/tmp/dist/unuforge-0.1.0-py3-none-any.whl"},
        )

    def test_main_requires_wheel_argument(self) -> None:
        module = _load_script_module()

        with self.assertRaises(SystemExit) as raised:
            module.main([])

        self.assertEqual(raised.exception.code, 2)


if __name__ == "__main__":
    unittest.main()
