from __future__ import annotations

import importlib.util
import io
import urllib.error
from pathlib import Path


def _load_renderer_module():
    script = Path(__file__).resolve().parents[1] / "scripts" / "render_homebrew_formula.py"
    spec = importlib.util.spec_from_file_location("render_homebrew_formula", script)
    assert spec and spec.loader
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)  # type: ignore[assignment]
    return module


def test_normalize_name() -> None:
    module = _load_renderer_module()
    assert module._normalize_name("Pydantic_Core") == "pydantic-core"
    assert module._normalize_name("typing.extensions") == "typing-extensions"


def test_render_formula_includes_resources_without_rust() -> None:
    module = _load_renderer_module()
    formula = module._render_formula(
        package_version="0.1.1",
        package_url="https://files.pythonhosted.org/foldermix-0.1.1.tar.gz",
        package_sha256="abc123",
        resources=[
            (
                "typer",
                "https://files.pythonhosted.org/typer-0.20.0.tar.gz",
                "r1",
            ),
            (
                "rich",
                "https://files.pythonhosted.org/rich-14.0.0.tar.gz",
                "r2",
            ),
        ],
    )

    assert 'depends_on "python@3.12"' in formula
    assert 'depends_on "rust" => :build' not in formula
    assert 'resource "typer" do' in formula
    assert 'resource "rich" do' in formula
    assert "virtualenv_install_with_resources" in formula
    assert 'assert_match "foldermix #{version}"' in formula


def test_fetch_retries_on_http_5xx_and_succeeds(monkeypatch) -> None:
    module = _load_renderer_module()
    calls = {"count": 0}
    sleeps: list[int] = []

    def fake_sleep(seconds: int) -> None:
        sleeps.append(seconds)

    class _Resp:
        def __enter__(self):
            return io.StringIO(
                '{"urls":[{"packagetype":"sdist","url":"https://files/a.tar.gz","digests":{"sha256":"abc"}}]}'
            )

        def __exit__(self, exc_type, exc, tb):
            return False

    def fake_urlopen(req, timeout=20):
        calls["count"] += 1
        if calls["count"] == 1:
            raise urllib.error.HTTPError(req.full_url, 503, "Service Unavailable", {}, None)
        return _Resp()

    monkeypatch.setattr(module.time, "sleep", fake_sleep)
    monkeypatch.setattr(module.urllib.request, "urlopen", fake_urlopen)

    url, sha = module._fetch_pypi_release_file("foldermix", "0.1.1", retries=2)
    assert url == "https://files/a.tar.gz"
    assert sha == "abc"
    assert sleeps == [3]


def test_fetch_http_500_failure_mentions_url(monkeypatch) -> None:
    module = _load_renderer_module()

    def fake_urlopen(req, timeout=20):
        raise urllib.error.HTTPError(req.full_url, 500, "Internal Server Error", {}, None)

    monkeypatch.setattr(module.urllib.request, "urlopen", fake_urlopen)

    expected_url = "https://pypi.org/pypi/pkg/9.9.9/json"
    try:
        module._fetch_pypi_release_file("pkg", "9.9.9", retries=1)
    except RuntimeError as exc:
        text = str(exc)
        assert expected_url in text
        assert "HTTP 500" in text
    else:
        raise AssertionError("Expected RuntimeError")


def test_resolve_runtime_deps_installs_local_project(monkeypatch, tmp_path: Path) -> None:
    module = _load_renderer_module()
    project_root = tmp_path / "project"
    project_root.mkdir()

    commands: list[list[str]] = []

    def fake_run(cmd: list[str]) -> str:
        commands.append(cmd)
        if cmd[-2:] == ["freeze", "--all"]:
            return "\n".join(
                [
                    "foldermix==0.1.7",
                    "rich==14.3.3",
                    "pathspec==1.0.4",
                    "pip==25.0.0",
                ]
            )
        return ""

    monkeypatch.setattr(module, "_run", fake_run)
    monkeypatch.setattr(module.sys, "executable", "/usr/bin/python3")

    deps = module._resolve_runtime_deps(project_root)

    assert ("pathspec", "1.0.4") in deps
    assert ("rich", "14.3.3") in deps
    assert ("foldermix", "0.1.7") not in deps
    assert any(len(cmd) >= 3 and cmd[1:3] == ["-m", "venv"] for cmd in commands)
    assert any(str(project_root) in cmd for cmd in commands)
