#!/usr/bin/env bash

if [[ "$(uname)" != "Darwin" ]]; then
  exit 0
fi

python3 - "$PWD" <<'PYTHON'
import json
import os
from pathlib import Path
import subprocess
import sys
import threading
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer

root = Path(sys.argv[1]).resolve()
prefix = root / "brew-prefix"
requests = []
BULK_PATH = "/api/cask.json"
cases = {
    "case-only": ("Example.app", "example.app"),
    "unicode": ("Caf\u00e9.app", "Cafe\u0301.app"),
    "unicode-case": ("CAF\u00c9.app", "cafe\u0301.app"),
    "case-fold-beta": ("\u03d0.app", "\u03b2.app"),
    "case-fold-sigma": ("\u03c2.app", "\u03c3.app"),
    "case-fold-expansion": ("Stra\u00dfe.app", "STRASSE.app"),
}


class Handler(BaseHTTPRequestHandler):
    def log_message(self, *args):
        pass

    def do_GET(self):
        requests.append(self.path)
        # The bulk cask index is probed before the per-cask endpoint. This
        # fixture does not publish one, which is an ordinary answer: mise falls
        # back to the per-cask request below, which is what this test exercises.
        # 404 rather than the 500 used for genuine violations, so a real
        # dependency or archive fetch still fails loudly.
        if self.path == BULK_PATH:
            self.send_error(404)
            return
        token = self.path.removeprefix("/api/cask/").removesuffix(".json")
        if self.path != f"/api/cask/{token}.json" or token not in cases:
            self.send_error(500, "must reject duplicate targets before fetching dependencies or archive")
            return
        first, second = cases[token]
        body = json.dumps({
            "token": token, "version": "1", "sha256": "no_check",
            "url": f"{base}/payload.zip",
            "depends_on": {"cask": ["must-not-install"]},
            "artifacts": [{"app": [f"one/{first}"]}, {"app": [f"two/{second}"]}],
        }).encode()
        self.send_response(200)
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)


server = ThreadingHTTPServer(("127.0.0.1", 0), Handler)
base = f"http://127.0.0.1:{server.server_port}"
env = dict(os.environ, MISE_SYSTEM_BREW_PREFIX=str(prefix),
           MISE_BREW_CASK_OPT_APPDIR=str(prefix / "Applications"),
           MISE_URL_REPLACEMENTS=json.dumps({"https://formulae.brew.sh": base}))
thread = threading.Thread(target=server.serve_forever, daemon=True)
thread.start()
runs = 0
try:
    for token, (_, second) in cases.items():
        (root / "mise.toml").write_text(
            f'[settings]\nexperimental = true\n[bootstrap.packages]\n"brew-cask:{token}" = "latest"\n'
        )
        for options in [("--dry-run",), ()]:
            command = ["mise", "bootstrap", "packages", "apply", "--yes", *options]
            result = subprocess.run(command, env=env, text=True, capture_output=True, timeout=30)
            runs += 1
            output = result.stdout + result.stderr
            print("$ " + " ".join(command), flush=True)
            print(output, end="", flush=True)
            assert result.returncode != 0, output
            assert "duplicate app target" in output, output
            assert second in output, output
            assert not prefix.exists(), "duplicate targets must fail before prefix or Caskroom creation"
    # Every cask is still resolved through its own endpoint, and nothing beyond
    # that is fetched.
    per_cask = [path for path in requests if path != BULK_PATH]
    assert set(per_cask) == {f"/api/cask/{token}.json" for token in cases}, requests

    # Count the bulk probes rather than folding them into a set, which would hide
    # how many there were. This fixture answers 404, so the cache never warms and
    # every process retries: exactly one attempt per process is the contract.
    #
    # Note that this cannot distinguish per-process from per-lookup on its own,
    # because each invocation here declares a single cask and fails before
    # dependency resolution. The memoization is pinned by the no-bulk phase of
    # test_system_brew_cask_bulk_index_macos, which resolves two casks in one
    # process. What this does catch is the count drifting at all: a retry loop,
    # or a probe per artifact rather than per package.
    bulk = [path for path in requests if path == BULK_PATH]
    assert len(bulk) == runs, (len(bulk), runs, requests)
finally:
    server.shutdown()
    thread.join()
    server.server_close()
PYTHON
