"""Regression test: google-workspace setup.py REQUIRED_PACKAGES must pin httplib2.

GHSA-j5g9-f88f-gfj3 (HIGH) — Decompression Bomb DoS via unbounded gzip/deflate
response handling.  Fixed in httplib2 0.32.0.

There are three install paths for google-workspace dependencies:
  1. pyproject.toml [project.optional-dependencies].google
  2. tools/lazy_deps.py LAZY_DEPS['skill.google_workspace']
  3. skills/productivity/google-workspace/scripts/setup.py REQUIRED_PACKAGES

This test ensures path 3 stays pinned and consistent with the other two.
"""

from __future__ import annotations

import ast
from pathlib import Path

REPO_ROOT = Path(__file__).resolve().parents[2]

SETUP_PY = REPO_ROOT / "skills/productivity/google-workspace/scripts/setup.py"
PYPROJECT_TOML = REPO_ROOT / "pyproject.toml"

# ---------------------------------------------------------------------------
# Static parsers
# ---------------------------------------------------------------------------

_GOOGLE_EXTRA_KEY = "google"
_LAZY_DEPS_KEY = "skill.google_workspace"


def _parse_setup_py_required_packages() -> list[str]:
    """Parse setup.py and return the REQUIRED_PACKAGES list."""
    tree = ast.parse(SETUP_PY.read_text(encoding="utf-8"))
    for node in ast.walk(tree):
        if isinstance(node, ast.Assign):
            for target in node.targets:
                if isinstance(target, ast.Name) and target.id == "REQUIRED_PACKAGES":
                    if isinstance(node.value, ast.List):
                        return [elt.value for elt in node.value.elts if isinstance(elt, ast.Constant)]
    raise AssertionError("REQUIRED_PACKAGES not found in setup.py")


def _parse_pyproject_google_extra() -> list[str]:
    """Parse pyproject.toml and return the google extra dependency list."""
    try:
        import tomllib
    except ImportError:
        import tomli as tomllib  # type: ignore[no-redef]
    data = tomllib.loads(PYPROJECT_TOML.read_text(encoding="utf-8"))
    optional_deps = data["project"]["optional-dependencies"]
    return list(optional_deps[_GOOGLE_EXTRA_KEY])


def _parse_lazy_deps_google_workspace() -> list[str]:
    """Return the real LAZY_DEPS entry for skill.google_workspace."""
    from tools.lazy_deps import LAZY_DEPS

    return list(LAZY_DEPS[_LAZY_DEPS_KEY])


def _extract_pins(packages: list[str]) -> dict[str, str]:
    """Extract pinned versions: {package_name: version} for entries with == pin."""
    pins: dict[str, str] = {}
    for pkg in packages:
        if "==" in pkg:
            name, version = pkg.split("==", 1)
            pins[name.strip()] = version.strip()
    return pins


# ---------------------------------------------------------------------------
# Tests
# ---------------------------------------------------------------------------


class TestGoogleWorkspaceSetupDepsPins:
    """Security pin consistency across all three google-workspace install paths."""

    def test_setup_py_pins_httplib2(self):
        """setup.py REQUIRED_PACKAGES must pin httplib2 at or above the GHSA fix version."""
        packages = _parse_setup_py_required_packages()
        pins = _extract_pins(packages)
        assert "httplib2" in pins, (
            f"httplib2 not found in setup.py REQUIRED_PACKAGES.\n"
            f"  Current entries: {packages}"
        )
        # GHSA-j5g9-f88f-gfj3 is fixed in 0.32.0 — floor invariant, not a snapshot,
        # so future bumps don't break this test.
        pinned = tuple(int(part) for part in pins["httplib2"].split("."))
        assert pinned >= (0, 32, 0), (
            f"httplib2 pin {pins['httplib2']} in setup.py is below 0.32.0, the "
            f"GHSA-j5g9-f88f-gfj3 fix version.\n"
            f"  Full REQUIRED_PACKAGES: {packages}"
        )

    def test_setup_py_pins_match_pyproject_toml(self):
        """httplib2 pin in setup.py must match pyproject.toml google extra."""
        required_packages = _parse_setup_py_required_packages()
        pyproject_packages = _parse_pyproject_google_extra()

        required_pins = _extract_pins(required_packages)
        pyproject_pins = _extract_pins(pyproject_packages)

        for pkg in ("httplib2", "google-api-python-client", "google-auth-oauthlib", "google-auth-httplib2"):
            setup_ver = required_pins.get(pkg)
            toml_ver = pyproject_pins.get(pkg)
            if setup_ver is None and toml_ver is None:
                continue  # neither path pins it, skip
            assert toml_ver is not None, (
                f"{pkg} is pinned in setup.py ({setup_ver}) but NOT in pyproject.toml google extra.\n"
                f"  setup.py: {required_pins}\n"
                f"  pyproject.toml google: {pyproject_pins}"
            )
            assert setup_ver is not None, (
                f"{pkg} is pinned in pyproject.toml ({toml_ver}) but NOT in setup.py.\n"
                f"  pyproject.toml google: {pyproject_pins}\n"
                f"  setup.py: {required_pins}"
            )
            assert setup_ver == toml_ver, (
                f"{pkg} pin mismatch: setup.py has {setup_ver}, pyproject.toml has {toml_ver}.\n"
                f"  setup.py: {required_pins}\n"
                f"  pyproject.toml google: {pyproject_pins}"
            )

    def test_setup_py_pins_match_lazy_deps(self):
        """httplib2 pin in setup.py must match tools/lazy_deps.py skill.google_workspace."""
        required_packages = _parse_setup_py_required_packages()
        lazy_packages = _parse_lazy_deps_google_workspace()

        required_pins = _extract_pins(required_packages)
        lazy_pins = _extract_pins(lazy_packages)

        for pkg in ("httplib2", "google-api-python-client", "google-auth-oauthlib", "google-auth-httplib2"):
            setup_ver = required_pins.get(pkg)
            lazy_ver = lazy_pins.get(pkg)
            if setup_ver is None and lazy_ver is None:
                continue
            assert lazy_ver is not None, (
                f"{pkg} is pinned in setup.py ({setup_ver}) but NOT in lazy_deps.py.\n"
                f"  setup.py: {required_pins}\n"
                f"  lazy_deps.py: {lazy_pins}"
            )
            assert setup_ver is not None, (
                f"{pkg} is pinned in lazy_deps.py ({lazy_ver}) but NOT in setup.py.\n"
                f"  lazy_deps.py: {lazy_pins}\n"
                f"  setup.py: {required_pins}"
            )
            assert setup_ver == lazy_ver, (
                f"{pkg} pin mismatch: setup.py has {setup_ver}, lazy_deps.py has {lazy_ver}.\n"
                f"  setup.py: {required_pins}\n"
                f"  lazy_deps.py: {lazy_pins}"
            )

    def test_all_google_packages_are_pinned_in_all_paths(self):
        """Every google workspace package that is version-pinned in any path must appear in all three."""
        pyproject_packages = _parse_pyproject_google_extra()
        lazy_packages = _parse_lazy_deps_google_workspace()
        setup_packages = _parse_setup_py_required_packages()

        all_pins: dict[str, set[str]] = {}
        for label, pkgs in [
            ("pyproject.toml", pyproject_packages),
            ("lazy_deps.py", lazy_packages),
            ("setup.py", setup_packages),
        ]:
            for pkg in pkgs:
                if "==" in pkg:
                    name, ver = pkg.split("==", 1)
                    all_pins.setdefault(name.strip(), set()).add(f"{label}={ver.strip()}")

        for pkg, entries in sorted(all_pins.items()):
            versions = {e.split("=", 1)[1] for e in entries}
            assert len(versions) == 1, (
                f"{pkg} has inconsistent pins across install paths:\n"
                + "\n".join(f"  {e}" for e in sorted(entries))
            )
            assert len(entries) == 3, (
                f"{pkg} is not pinned in all three install paths.  Found {len(entries)}/3:\n"
                + "\n".join(f"  {e}" for e in sorted(entries))
            )
