import sys
import platform
import sysconfig
import requests
from packaging.version import Version
from packaging.specifiers import SpecifierSet


def get_current_environment() -> dict:
    """Snapshot of the current Python + platform environment."""
    return {
        "python_version": Version(platform.python_version()),
        "platform_system": platform.system().lower(),       # 'linux', 'windows', 'darwin'
        "platform_machine": platform.machine().lower(),     # 'x86_64', 'arm64', etc.
        "platform_tags": _get_platform_tags(),
    }


def _get_platform_tags() -> list[str]:
    """Get the list of compatible wheel platform tags for this system."""
    try:
        from pip._internal.utils.compatibility_tags import get_supported
        return [str(tag) for tag in get_supported()]
    except ImportError:
        # Fallback: construct basic tags manually
        py = f"cp{sys.version_info.major}{sys.version_info.minor}"
        arch = sysconfig.get_platform().replace("-", "_").replace(".", "_")
        return [f"{py}-{py}-{arch}", f"py3-none-any", f"py{sys.version_info.major}-none-any"]


def fetch_package_metadata(package_name: str, version: str = None) -> dict | None:
    """Fetch package metadata from PyPI JSON API."""
    url = f"https://pypi.org/pypi/{package_name}/json"
    if version:
        url = f"https://pypi.org/pypi/{package_name}/{version}/json"

    try:
        resp = requests.get(url, timeout=10)
        resp.raise_for_status()
        return resp.json()
    except requests.RequestException:
        return None


def check_python_compatibility(package_name: str, version: str = None) -> dict:
    """
    Check if a package is compatible with the current Python version.
    Returns a result dict with 'compatible', 'requires_python', and optionally 'suggested_version'.
    """
    env = get_current_environment()
    metadata = fetch_package_metadata(package_name, version)

    if metadata is None:
        return {"compatible": None, "error": f"Could not fetch metadata for '{package_name}'"}

    info = metadata["info"]
    requires_python = info.get("requires_python")

    if not requires_python:
        return {"compatible": True, "requires_python": None}

    spec = SpecifierSet(requires_python)
    compatible = env["python_version"] in spec

    result = {
        "compatible": compatible,
        "requires_python": requires_python,
        "current_python": str(env["python_version"]),
    }

    if not compatible:
        # Try to find the latest version that does support this Python
        suggested = _find_compatible_version(metadata["releases"], spec, env["python_version"])
        result["suggested_version"] = suggested

    return result


def _find_compatible_version(releases: dict, broken_spec: SpecifierSet, current_python: Version) -> str | None:
    """
    Walk all available releases and return the latest one compatible
    with the current Python version.
    """
    candidates = []

    for ver_str, files in releases.items():
        if not files:
            continue
        try:
            v = Version(ver_str)
        except Exception:
            continue

        # Check each release file for its requires_python
        for f in files:
            rp = f.get("requires_python")
            if rp is None:
                candidates.append(v)
                break
            try:
                if current_python in SpecifierSet(rp):
                    candidates.append(v)
                    break
            except Exception:
                continue

    if not candidates:
        return None

    return str(max(candidates))


def check_platform_compatibility(package_name: str, version: str = None) -> dict:
    """
    Check if any wheel for this package supports the current platform.
    Falls back to sdist detection if no compatible wheel is found.
    """
    env = get_current_environment()
    metadata = fetch_package_metadata(package_name, version)

    if metadata is None:
        return {"compatible": None, "error": f"Could not fetch metadata for '{package_name}'"}

    target_version = version or metadata["info"]["version"]
    release_files = metadata["releases"].get(target_version, [])

    has_sdist = False
    has_compatible_wheel = False
    has_any_wheel = False

    for f in release_files:
        if f["packagetype"] == "sdist":
            has_sdist = True
        elif f["packagetype"] == "bdist_wheel":
            has_any_wheel = True
            filename = f["filename"]
            # Check platform tag compatibility
            if _wheel_is_compatible(filename, env["platform_tags"]):
                has_compatible_wheel = True

    return {
        "has_compatible_wheel": has_compatible_wheel,
        "has_sdist": has_sdist,
        "has_any_wheel": has_any_wheel,
        "needs_compilation": has_sdist and not has_compatible_wheel,
        "platform": env["platform_system"],
        "machine": env["platform_machine"],
    }


def _wheel_is_compatible(filename: str, supported_tags: list[str]) -> bool:
    """Check if a wheel filename's tags match any of the supported platform tags."""
    # Wheel filename format: {name}-{version}(-{build})?-{python}-{abi}-{platform}.whl
    try:
        base = filename.replace(".whl", "")
        parts = base.split("-")
        if len(parts) < 5:
            return False
        py_tag, abi_tag, plat_tag = parts[-3], parts[-2], parts[-1]
        wheel_tag = f"{py_tag}-{abi_tag}-{plat_tag}"

        # Pure Python wheels are always compatible
        if "none-any" in wheel_tag:
            return True

        return wheel_tag in supported_tags
    except Exception:
        return False