"""Real pinned SDK setup reuses restored bytes and refetches only what a cache miss needs."""
import hashlib
import io
import json
import os
from pathlib import Path
import subprocess
import sys
import tarfile
import tempfile
import threading
import unittest
import urllib.request
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer

SETUP_SHA = "35f0cd9e9c1d7a643448223573b4a03879e63676fdc27872de3d0104d5bf89f9"
SETUP_URL = ("https://raw.githubusercontent.com/subosito/flutter-action/"
             "1a449444c387b1966244ae4d4f8c696479add0b2/setup.sh")


class SdkSetupTests(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        fixture = os.environ.get("GOWALK_CACHE_ACTION_FIXTURES")
        if fixture:
            cls.source = (Path(fixture) / "flutter-setup.sh").read_bytes()
        else:
            with urllib.request.urlopen(SETUP_URL, timeout=30) as response:
                cls.source = response.read(128 * 1024)
        assert hashlib.sha256(cls.source).hexdigest() == SETUP_SHA

    def setUp(self):
        self.directory = tempfile.TemporaryDirectory()
        self.addCleanup(self.directory.cleanup)
        self.path = Path(self.directory.name)
        self.setup = self.path / "setup.sh"
        self.setup.write_bytes(self.source)
        self.sdk = self.path / "sdk"
        self.env = {**os.environ, "RUNNER_TEMP": str(self.path), "RUNNER_OS": "Linux", "RUNNER_ARCH": "X64",
                    "RUNNER_TOOL_CACHE": str(self.path / "tools"), "PUB_CACHE": str(self.path / "pub"),
                    "GITHUB_ENV": str(self.path / "env"),
                    "GITHUB_OUTPUT": str(self.path / "output"), "GITHUB_PATH": str(self.path / "path")}
        self.calls = []
        body = io.BytesIO()
        with tarfile.open(fileobj=body, mode="w:gz") as archive:
            entry = tarfile.TarInfo("flutter/bin/flutter")
            content = b"#!/bin/sh\nexit 0\n"
            entry.size, entry.mode = len(content), 0o755
            archive.addfile(entry, io.BytesIO(content))
        self.archive = body.getvalue()
        self.server = ThreadingHTTPServer(("127.0.0.1", 0), self.handler())
        threading.Thread(target=self.server.serve_forever, daemon=True).start()
        self.addCleanup(self.server.server_close)
        self.addCleanup(self.server.shutdown)
        self.origin = f"http://127.0.0.1:{self.server.server_port}"
        self.env["FLUTTER_STORAGE_BASE_URL"] = self.origin

    def handler(self):
        owner = self

        class Handler(BaseHTTPRequestHandler):
            def do_GET(self):
                owner.calls.append(self.path)
                if self.path.endswith(".json"):
                    data = json.dumps({"releases": [{"channel": "stable", "version": "3.44.0",
                        "dart_sdk_arch": "x64", "hash": "fixture", "sha256": "fixture",
                        "archive": "sdk.tar.gz"}]}).encode()
                else:
                    data = owner.archive
                self.send_response(200)
                self.send_header("Content-Length", str(len(data)))
                self.end_headers()
                self.wfile.write(data)

            def log_message(self, *_args):
                pass

        return Handler

    def install(self):
        return subprocess.run(["bash", str(self.setup), "-n", "3.44.0", "-a", "x64", "-c", str(self.sdk),
                               "stable"], env=self.env, capture_output=True, text=True, timeout=10)

    def test_restored_sdk_fetches_only_the_manifest(self):
        target = self.sdk / "flutter/bin/flutter"
        target.parent.mkdir(parents=True)
        target.write_text("#!/bin/sh\nexit 0\n")
        target.chmod(0o755)
        result = self.install()
        self.assertEqual(result.returncode, 0, result.stderr)
        self.assertEqual(self.calls, ["/flutter_infra_release/releases/releases_linux.json"])

    def test_cold_cache_downloads_and_installs_the_sdk(self):
        result = self.install()
        self.assertEqual(result.returncode, 0, result.stderr)
        self.assertEqual([url.rsplit("/", 1)[-1] for url in self.calls], ["releases_linux.json", "sdk.tar.gz"])
        self.assertTrue(os.access(self.sdk / "flutter/bin/flutter", os.X_OK))

    def test_provider_failure_after_cache_miss_still_fails_setup(self):
        self.archive = b"not-a-valid-sdk-archive"
        result = self.install()
        self.assertNotEqual(result.returncode, 0)
        self.assertFalse((self.sdk / "flutter/bin/flutter").exists())
        self.assertEqual(len(self.calls), 2)


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