"""Real curl and jq execute the byte-identical official setup against owned TLS failures."""
import os
from pathlib import Path
import subprocess
import tempfile
import unittest

import flutter_manifest

from flutter_manifest_fixture import MANIFEST, official_setup, tls_origin

ROOT = Path(__file__).parent


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

    def setUp(self):
        self.directory = tempfile.TemporaryDirectory()
        self.addCleanup(self.directory.cleanup)
        self.root = Path(self.directory.name)
        self.setup = self.root / "setup.sh"
        self.setup.write_bytes(self.source)
        (self.root / "test").mkdir()
        (self.root / "test/releases_linux.json").write_bytes(MANIFEST)
        # Local curl preferences may never disable the recovery helper's certificate checks.
        (self.root / ".curlrc").write_text("insecure\n")

    def invoke(self, server, cert, *, hooked=True, trusted=True, test_mode=False):
        env = {**os.environ, "HOME": str(self.root), "RUNNER_TEMP": str(self.root), "RUNNER_OS": "Linux",
               "RUNNER_ARCH": "X64", "RUNNER_TOOL_CACHE": str(self.root / "tools"),
               "PUB_CACHE": str(self.root / "pub"), "FLUTTER_STORAGE_BASE_URL": server.url(""),
               "GITHUB_OUTPUT": str(self.root / "output")}
        for key in ("BASH_ENV", "CURL_CA_BUNDLE", "SSL_CERT_FILE", "SSL_CERT_DIR",
                    "HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy", "ALL_PROXY", "all_proxy"):
            env.pop(key, None)
        if trusted:
            env["CURL_CA_BUNDLE"] = str(cert)
        if hooked:
            env.update(BASH_ENV=str(ROOT / "flutter_manifest_env.sh"),
                       GOWALK_FLUTTER_MANIFEST_HELPER=str(ROOT / "flutter_manifest.py"))
        else:
            # The baseline deliberately runs the original curl defaults, without a local .curlrc.
            env.update(HOME=str(self.root / "absent-home"))
        args = ["bash", str(self.setup), "-p", "-n", "3.44.0", "-a", "x64", "-k", "custom-:version:-:hash:"]
        result = subprocess.run([*args, *(["-t"] if test_mode else []), "stable"], env=env,
                                capture_output=True, text=True, timeout=120)
        self.assertFalse(list(self.root.glob("flutter-manifest-*")))
        return result

    def test_original_tls_reset_recovers_without_changing_official_cache_identity(self):
        with tls_origin(self.root, ["reset"]) as (server, cert):
            original = self.invoke(server, cert, hooked=False)
            self.assertEqual(original.returncode, 35)
            self.assertEqual((server.connects, server.requests), (1, []))
        with tls_origin(self.root, ["reset", "ok"]) as (server, cert):
            result = self.invoke(server, cert)
            self.assertEqual(result.returncode, 0, result.stderr)
            self.assertEqual((server.connects, len(server.requests)), (2, 1))
            self.assertIn("flutter_manifest_recovered attempts=2", result.stderr)
            baseline = self.invoke(server, cert, test_mode=True)
        self.assertEqual((self.root / "output").read_text(), baseline.stdout)
        self.assertEqual(result.stdout, "")

    def test_partial_body_is_discarded_before_the_next_complete_json(self):
        with tls_origin(self.root, ["partial", "ok"]) as (server, cert):
            result = self.invoke(server, cert)
            self.assertEqual(result.returncode, 0, result.stderr)
            self.assertEqual((server.connects, len(server.requests)), (2, 2))
        self.assertIn("VERSION=3.44.0", (self.root / "output").read_text())
        self.assertEqual(result.stdout, "")

    def test_untrusted_certificate_never_retries_or_uses_curlrc_insecure(self):
        with tls_origin(self.root, ["ok"]) as (server, cert):
            result = self.invoke(server, cert, trusted=False)
            self.assertEqual(result.returncode, 60)
            self.assertEqual((server.connects, server.requests), (1, []))
        self.assertIn("attempts=1", result.stderr)
        self.assertEqual(result.stdout, "")

    def test_origin_auth_is_terminal_without_exposing_its_body(self):
        with tls_origin(self.root, ["origin_auth"]) as (server, cert):
            result = self.invoke(server, cert)
            self.assertEqual(result.returncode, 22)
            self.assertEqual((server.connects, len(server.requests)), (1, 1))
        self.assertIn("http_status=401", result.stderr)
        self.assertIn("attempts=1", result.stderr)
        self.assertEqual(result.stdout, "")

    def test_repeated_tls_resets_are_retried_across_the_manifest_window(self):
        """An origin that refuses TLS is retried until the manifest's own deadline,
        not abandoned after four handshakes: obd-scanner's iOS release lost its
        manifest to four refusals in ten seconds with fifty seconds of its
        sixty-second budget unspent, an hour after the same fetch succeeded
        (2026-09-09). Nothing is ever published from a refused attempt."""
        limit = flutter_manifest.MAX_ATTEMPTS["manifest"]
        with tls_origin(self.root, ["reset"] * limit) as (server, cert):
            result = self.invoke(server, cert)
            self.assertEqual(result.returncode, 35)
            self.assertEqual((server.connects, server.requests), (limit, []))
        self.assertIn(f"attempts={limit}", result.stderr)
        self.assertEqual(result.stdout, "")


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