from __future__ import annotations

import platform
import sys
import sysconfig

import pytest

ANDROID = sys.platform.startswith("android")
IOS = sys.platform.startswith("ios")
LINUX = sys.platform.startswith("linux")
MACOS = sys.platform.startswith("darwin")
WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin")
FREEBSD = sys.platform.startswith("freebsd")

MUSLLINUX = False
MANYLINUX = False
if LINUX:

    def _is_musl() -> bool:
        libc, _ = platform.libc_ver()
        return libc == "musl" or (libc != "glibc" and libc != "")

    MUSLLINUX = _is_musl()
    MANYLINUX = not MUSLLINUX
    del _is_musl

CPYTHON = platform.python_implementation() == "CPython"
PYPY = platform.python_implementation() == "PyPy"
PYPY_PRE_7_3_23 = PYPY and sys.pypy_version_info < (7, 3, 23)
GRAALPY = sys.implementation.name == "graalpy"

# Compile-time config (what the binary was built for)
PY_GIL_DISABLED = bool(sysconfig.get_config_var("Py_GIL_DISABLED"))
# Runtime state (what's actually happening now)
sys_is_gil_enabled = getattr(sys, "_is_gil_enabled", lambda: True)

TYPES_ARE_IMMORTAL = (
    PYPY
    or GRAALPY
    or (CPYTHON and PY_GIL_DISABLED and (3, 13) <= sys.version_info < (3, 14))
)


def check_script_success_in_subprocess(code: str, *, rerun: int = 8) -> None:
    """Runs the given code in a subprocess."""
    import os
    import subprocess
    import sys
    import textwrap

    if ANDROID or IOS or sys.platform.startswith("emscripten"):
        pytest.skip("Requires subprocess support")

    code = textwrap.dedent(code).strip()
    try:
        for _ in range(rerun):  # run flakily failing test multiple times
            subprocess.check_output(
                [sys.executable, "-c", code],
                cwd=os.getcwd(),
                stderr=subprocess.STDOUT,
                text=True,
            )
    except subprocess.CalledProcessError as ex:
        raise RuntimeError(
            f"Subprocess failed with exit code {ex.returncode}.\n\n"
            f"Code:\n"
            f"```python\n"
            f"{code}\n"
            f"```\n\n"
            f"Output:\n"
            f"{ex.output}"
        ) from None
