"""Exact pinned setup survives a manifest outage after a verified resolution."""
import json
import os
from pathlib import Path
import subprocess
import tempfile
import unittest

from flutter_manifest_fixture import official_setup, tls_origin

ROOT = Path(__file__).parent


class ReleaseCacheTests(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.source = official_setup()

    def setUp(self):
        scratch = tempfile.TemporaryDirectory()
        self.addCleanup(scratch.cleanup)
        self.root = Path(scratch.name)
        self.setup = self.root / "setup.sh"
        self.setup.write_bytes(self.source)
        self.cache = self.root / "gowalk-flutter-manifests" / ("a" * 64 + ".json")

    def invoke(self, server, cert, *, version="3.44.0"):
        pin = {"version": version, "channel": "stable", "architecture": "x64"}
        env = {**os.environ, "RUNNER_TEMP": str(self.root), "RUNNER_OS": "Linux", "RUNNER_ARCH": "X64",
               "RUNNER_TOOL_CACHE": str(self.root / "tools"), "GITHUB_OUTPUT": str(self.root / "output"),
               "PUB_CACHE": str(self.root / "pub"), "FLUTTER_STORAGE_BASE_URL": server.url(""),
               "BASH_ENV": str(ROOT / "flutter_manifest_env.sh"), "CURL_CA_BUNDLE": str(cert),
               "GOWALK_FLUTTER_MANIFEST_HELPER": str(ROOT / "flutter_manifest.py"),
               "GOWALK_FLUTTER_RELEASE_CACHE": str(self.cache), "GOWALK_FLUTTER_RELEASE_PIN": json.dumps(pin)}
        for name in ("HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy"):
            env.pop(name, None)
        (self.root / "output").write_text("")
        return subprocess.run(["bash", str(self.setup), "-p", "-n", version, "-a", "x64",
                               "-k", "same-:version:-:hash:", "stable"], env=env,
                              capture_output=True, text=True, timeout=15)

    def test_warm_resolution_preserves_sdk_identity_without_another_manifest_connection(self):
        with tls_origin(self.root, ["ok", "origin_auth"]) as (server, cert):
            cold = self.invoke(server, cert)
            self.assertEqual(cold.returncode, 0, cold.stderr)
            identity = (self.root / "output").read_text()
            warm = self.invoke(server, cert)
            self.assertEqual(warm.returncode, 0, warm.stderr)
            self.assertEqual((server.connects, len(server.requests)), (1, 1))
            self.assertEqual((self.root / "output").read_text(), identity)
            self.assertIn("flutter_manifest_cache", warm.stderr)

    def test_changed_pin_does_not_reuse_another_versions_manifest(self):
        with tls_origin(self.root, ["ok", "origin_auth"]) as (server, cert):
            self.assertEqual(self.invoke(server, cert).returncode, 0)
            changed = self.invoke(server, cert, version="3.44.1")
            self.assertNotEqual(changed.returncode, 0)
            self.assertEqual(server.connects, 2)
            self.assertIn("http_status=401", changed.stderr)

    def test_invalid_cache_is_recovered_with_a_fresh_provider_read(self):
        self.cache.parent.mkdir()
        self.cache.write_text("truncated JSON")
        with tls_origin(self.root, ["ok"]) as (server, cert):
            result = self.invoke(server, cert)
            self.assertEqual(result.returncode, 0, result.stderr)
            self.assertEqual(server.connects, 1)
        self.assertEqual(json.loads(self.cache.read_text())["pin"]["version"], "3.44.0")

    def test_wrong_origin_or_invalid_release_metadata_requires_a_fresh_provider_read(self):
        for change in ["url", "sha256"]:
            with self.subTest(change=change), tls_origin(self.root, ["ok", "ok"]) as (server, cert):
                self.cache.unlink(missing_ok=True)
                self.assertEqual(self.invoke(server, cert).returncode, 0)
                record = json.loads(self.cache.read_text())
                if change == "url":
                    record["url"] = "https://another.fixture.invalid/releases_linux.json"
                else:
                    record["manifest"]["releases"][0]["sha256"] = "invalid"
                self.cache.write_text(json.dumps(record))
                self.assertEqual(self.invoke(server, cert).returncode, 0)
                self.assertEqual(server.connects, 2)

    def test_wildcard_selection_still_resolves_a_fresh_manifest(self):
        with tls_origin(self.root, ["ok", "origin_auth"]) as (server, cert):
            self.assertEqual(self.invoke(server, cert, version="3.44.x").returncode, 0)
            result = self.invoke(server, cert, version="3.44.x")
            self.assertNotEqual(result.returncode, 0)
            self.assertEqual(server.connects, 2)
        self.assertFalse(self.cache.exists())


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