# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""Tests verifying that the LibDescriptor registry faithfully represents
the existing data tables in supported_nvidia_libs.py."""

import pytest

from cuda.pathfinder._dynamic_libs.lib_descriptor import LIB_DESCRIPTORS
from cuda.pathfinder._dynamic_libs.supported_nvidia_libs import (
    DIRECT_DEPENDENCIES,
    LIBNAMES_REQUIRING_OS_ADD_DLL_DIRECTORY,
    LIBNAMES_REQUIRING_RTLD_DEEPBIND,
    SITE_PACKAGES_LIBDIRS_LINUX,
    SITE_PACKAGES_LIBDIRS_WINDOWS,
    SITE_PACKAGES_LIBDIRS_WINDOWS_ARM64,
    SITE_PACKAGES_LIBDIRS_WINDOWS_CTK,
    SITE_PACKAGES_LIBDIRS_WINDOWS_CTK_X64,
    SITE_PACKAGES_LIBDIRS_WINDOWS_OTHER,
    SITE_PACKAGES_LIBDIRS_WINDOWS_OTHER_X64,
    SITE_PACKAGES_LIBDIRS_WINDOWS_X64,
    SUPPORTED_LIBNAMES,
    SUPPORTED_LIBNAMES_LINUX,
    SUPPORTED_LIBNAMES_WINDOWS,
    SUPPORTED_LIBNAMES_WINDOWS_ARM64,
    SUPPORTED_LIBNAMES_WINDOWS_X64,
    SUPPORTED_LINUX_SONAMES,
    SUPPORTED_WINDOWS_DLLS,
)
from cuda.pathfinder._utils.platform_aware import IS_WINDOWS, IS_WINDOWS_ARM64, IS_WINDOWS_X64

# ---------------------------------------------------------------------------
# Registry completeness
# ---------------------------------------------------------------------------


def test_registry_covers_all_linux_sonames():
    assert set(SUPPORTED_LINUX_SONAMES) <= set(LIB_DESCRIPTORS)


def test_registry_covers_all_windows_dlls():
    assert set(SUPPORTED_WINDOWS_DLLS) <= set(LIB_DESCRIPTORS)


def test_registry_has_no_extra_entries():
    expected = set(SUPPORTED_LINUX_SONAMES) | set(SUPPORTED_WINDOWS_DLLS)
    assert set(LIB_DESCRIPTORS) == expected


# ---------------------------------------------------------------------------
# Per-field consistency with source dicts
# ---------------------------------------------------------------------------


@pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS))
def test_linux_sonames_match(name):
    assert LIB_DESCRIPTORS[name].linux_sonames == SUPPORTED_LINUX_SONAMES.get(name, ())


@pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS))
def test_windows_dlls_match(name):
    assert LIB_DESCRIPTORS[name].windows_dlls == SUPPORTED_WINDOWS_DLLS.get(name, ())


@pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS))
def test_site_packages_linux_match(name):
    assert LIB_DESCRIPTORS[name].site_packages_linux == SITE_PACKAGES_LIBDIRS_LINUX.get(name, ())


@pytest.mark.parametrize(
    ("target_arch", "site_packages_libdirs"),
    [
        ("x64", SITE_PACKAGES_LIBDIRS_WINDOWS_X64),
        ("arm64", SITE_PACKAGES_LIBDIRS_WINDOWS_ARM64),
    ],
)
@pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS))
@pytest.mark.agent_authored(model="gpt-5")
def test_site_packages_windows_match(name, target_arch, site_packages_libdirs):
    assert LIB_DESCRIPTORS[name].site_packages_windows.for_arch(target_arch) == site_packages_libdirs.get(name, ())


@pytest.mark.agent_authored(model="gpt-5")
def test_legacy_site_packages_windows_tables_are_x64_aliases():
    assert SITE_PACKAGES_LIBDIRS_WINDOWS_CTK is SITE_PACKAGES_LIBDIRS_WINDOWS_CTK_X64
    assert SITE_PACKAGES_LIBDIRS_WINDOWS_OTHER is SITE_PACKAGES_LIBDIRS_WINDOWS_OTHER_X64
    assert SITE_PACKAGES_LIBDIRS_WINDOWS is SITE_PACKAGES_LIBDIRS_WINDOWS_X64


@pytest.mark.agent_authored(model="gpt-5")
def test_legacy_supported_libnames_windows_is_x64_alias():
    assert SUPPORTED_LIBNAMES_WINDOWS is SUPPORTED_LIBNAMES_WINDOWS_X64


@pytest.mark.agent_authored(model="gpt-5")
def test_supported_libnames_selects_current_platform_and_arch():
    if not IS_WINDOWS:
        expected = SUPPORTED_LIBNAMES_LINUX
    elif IS_WINDOWS_X64:
        expected = SUPPORTED_LIBNAMES_WINDOWS_X64
    else:
        assert IS_WINDOWS_ARM64
        expected = SUPPORTED_LIBNAMES_WINDOWS_ARM64
    assert SUPPORTED_LIBNAMES is expected


@pytest.mark.agent_authored(model="gpt-5")
def test_arch_specific_ctk_libname_projections():
    assert "cudla" not in SUPPORTED_LIBNAMES_WINDOWS_X64
    assert "cudla" in SUPPORTED_LIBNAMES_WINDOWS_ARM64
    assert "nvjpeg" in SUPPORTED_LIBNAMES_WINDOWS_X64
    assert "nvjpeg" in SUPPORTED_LIBNAMES_WINDOWS_ARM64


@pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS))
def test_dependencies_match(name):
    assert LIB_DESCRIPTORS[name].dependencies == DIRECT_DEPENDENCIES.get(name, ())


@pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS))
def test_requires_add_dll_directory_match(name):
    assert LIB_DESCRIPTORS[name].requires_add_dll_directory == (name in LIBNAMES_REQUIRING_OS_ADD_DLL_DIRECTORY)


@pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS))
def test_requires_rtld_deepbind_match(name):
    assert LIB_DESCRIPTORS[name].requires_rtld_deepbind == (name in LIBNAMES_REQUIRING_RTLD_DEEPBIND)


# ---------------------------------------------------------------------------
# Strategy classification
# ---------------------------------------------------------------------------


@pytest.mark.parametrize("name", sorted(SUPPORTED_LIBNAMES))
def test_ctk_libs_have_ctk_packaging(name):
    assert LIB_DESCRIPTORS[name].packaged_with == "ctk"


def test_other_libs_have_other_packaging():
    # Spot-check a few known "other" libs
    for name in ("nccl", "cutensor", "cusparseLt"):
        if name in LIB_DESCRIPTORS:
            assert LIB_DESCRIPTORS[name].packaged_with == "other", name


# ---------------------------------------------------------------------------
# Descriptor properties
# ---------------------------------------------------------------------------


def test_descriptor_is_frozen():
    desc = LIB_DESCRIPTORS["cudart"]
    with pytest.raises(AttributeError):
        desc.name = "bogus"  # type: ignore[misc]
