import hashlib
import importlib.util
import os
import pathlib
import tempfile
import unittest
from unittest import mock


class UpdateLockChecksumTest(unittest.TestCase):
    @staticmethod
    def load_update_lock_module():
        repo = pathlib.Path(__file__).resolve().parents[1]
        update_lock = repo / "scripts" / "update-lock.py"
        spec = importlib.util.spec_from_file_location("update_lock", update_lock)
        assert spec and spec.loader
        module = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(module)
        return module

    def test_update_lock_records_checksum_for_download_artifacts(self):
        update_lock = self.load_update_lock_module()

        with tempfile.TemporaryDirectory() as tmp:
            tmp_path = pathlib.Path(tmp)
            bin_dir = tmp_path / "bin"
            bin_dir.mkdir()
            artifact = tmp_path / "artifact.bin"
            artifact.write_text("checksum fixture\n", encoding="utf-8")
            expected = hashlib.sha256(artifact.read_bytes()).hexdigest()

            command = bin_dir / "foo"
            command.write_text("#!/usr/bin/env bash\necho 'foo 1.2.3'\n", encoding="utf-8")
            command.chmod(0o755)

            manifest = tmp_path / "deps.toml"
            manifest.write_text(
                """
[deps.foo]
command = "foo"
target = "latest"

[deps.foo.linux]
installer = "official_release"
source = "file://{artifact}"
""".strip().format(artifact=artifact),
                encoding="utf-8",
            )

            lock = tmp_path / "deps.lock"
            env = os.environ.copy()
            env["PATH"] = f"{bin_dir}:{env['PATH']}"

            with mock.patch.object(update_lock, "current_arch", return_value="arm64"):
                with mock.patch.object(update_lock, "checksum_for_source", return_value=expected):
                    with mock.patch.dict(os.environ, env, clear=False):
                        with mock.patch("sys.argv", [
                            "update-lock.py",
                            str(manifest),
                            str(lock),
                            "--platform",
                            "linux",
                            "--manifest-commit",
                            "test",
                        ]):
                            update_lock.main()

            text = lock.read_text(encoding="utf-8")
            self.assertIn('checksum = "', text)
            self.assertIn(expected, text)

    def test_update_lock_uses_pinned_target_for_release_urls(self):
        update_lock = self.load_update_lock_module()

        with tempfile.TemporaryDirectory() as tmp:
            tmp_path = pathlib.Path(tmp)
            bin_dir = tmp_path / "bin"
            bin_dir.mkdir()

            command = bin_dir / "nvim"
            command.write_text("#!/usr/bin/env bash\necho 'NVIM v0.12.2'\n", encoding="utf-8")
            command.chmod(0o755)

            manifest = tmp_path / "deps.toml"
            manifest.write_text(
                """
[deps.nvim]
command = "nvim"
target = "v0.12.2"

[deps.nvim.linux]
installer = "official_tarball"
source = "https://neovim.io/doc/install/"
""".strip(),
                encoding="utf-8",
            )

            lock = tmp_path / "deps.lock"
            env = os.environ.copy()
            env["PATH"] = f"{bin_dir}:{env['PATH']}"

            with mock.patch.object(update_lock, "current_arch", return_value="arm64"):
                with mock.patch.object(update_lock, "github_latest_tag", side_effect=AssertionError("latest tag lookup should not run for pinned targets")):
                    with mock.patch.object(update_lock, "checksum_for_source", return_value="deadbeef"):
                        with mock.patch.dict(os.environ, env, clear=False):
                            with mock.patch("sys.argv", [
                                "update-lock.py",
                                str(manifest),
                                str(lock),
                                "--platform",
                                "linux",
                                "--manifest-commit",
                                "test",
                            ]):
                                update_lock.main()

            text = lock.read_text(encoding="utf-8")
            self.assertIn('version = "NVIM v0.12.2"', text)
            self.assertIn('/releases/download/v0.12.2/', text)
            self.assertNotIn('/releases/latest/download/', text)


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