"""Tests for CLI environment detector network probing."""

from __future__ import annotations

from types import SimpleNamespace

from sagellm.cli.utils import env_detector


def test_check_connectivity_prefers_urllib_success(monkeypatch) -> None:
    monkeypatch.setattr(
        env_detector.NetworkDetector,
        "_check_connectivity_via_urllib",
        staticmethod(lambda _url, _timeout: True),
    )

    def _unexpected_run(*_args, **_kwargs):
        raise AssertionError("curl fallback should not run when urllib succeeds")

    monkeypatch.setattr(env_detector.subprocess, "run", _unexpected_run)

    assert env_detector.NetworkDetector.check_connectivity("https://huggingface.co") is True


def test_check_connectivity_uses_curl_fallback(monkeypatch) -> None:
    monkeypatch.setattr(
        env_detector.NetworkDetector,
        "_check_connectivity_via_urllib",
        staticmethod(lambda _url, _timeout: False),
    )

    monkeypatch.setattr(
        env_detector.subprocess,
        "run",
        lambda *_args, **_kwargs: SimpleNamespace(
            returncode=0,
            stdout=b"HTTP/2 200\r\n",
        ),
    )

    assert env_detector.NetworkDetector.check_connectivity("https://hf-mirror.com") is True


def test_check_connectivity_no_socket_false_positive_when_curl_missing(monkeypatch) -> None:
    monkeypatch.setattr(
        env_detector.NetworkDetector,
        "_check_connectivity_via_urllib",
        staticmethod(lambda _url, _timeout: False),
    )

    def _raise_missing(*_args, **_kwargs):
        raise FileNotFoundError("curl not found")

    monkeypatch.setattr(env_detector.subprocess, "run", _raise_missing)

    assert env_detector.NetworkDetector.check_connectivity("https://huggingface.co") is False


def test_detect_hf_endpoint_falls_back_to_mirror(monkeypatch) -> None:
    monkeypatch.delenv("HF_ENDPOINT", raising=False)

    calls = iter([False, True])
    monkeypatch.setattr(
        env_detector.NetworkDetector,
        "check_connectivity",
        staticmethod(lambda _url, timeout=5: next(calls)),
    )

    endpoint, is_official = env_detector.NetworkDetector.detect_hf_endpoint(verbose=False)

    assert endpoint == env_detector.NetworkDetector.HF_MIRROR
    assert is_official is False


def test_init_ascend_pythonpath_prepends_tbe_paths(monkeypatch, tmp_path) -> None:
    toolkit_home = tmp_path / "ascend-toolkit" / "8.0.RC3"
    runtime_dir = toolkit_home / "runtime"
    opp_dir = toolkit_home / "opp"
    tbe_site = toolkit_home / "python" / "site-packages" / "tbe"
    vector_tbe = toolkit_home / "opp" / "built-in" / "op_impl" / "vector_core" / "tbe"

    runtime_dir.mkdir(parents=True)
    opp_dir.mkdir(parents=True)
    tbe_site.mkdir(parents=True)
    vector_tbe.mkdir(parents=True)

    monkeypatch.setattr(env_detector.shutil, "which", lambda _cmd: "/usr/bin/npu-smi")
    monkeypatch.setattr(env_detector, "_iter_ascend_toolkit_homes", lambda: [toolkit_home])

    monkeypatch.setenv("PYTHONPATH", "/old/path")
    monkeypatch.delenv("ASCEND_RUNTIME_PATH", raising=False)
    monkeypatch.delenv("ASCEND_OPP_PATH", raising=False)

    env_detector.EnvInitializer.init_ascend_pythonpath()

    pythonpath = env_detector.os.environ.get("PYTHONPATH", "")
    assert str(toolkit_home / "python" / "site-packages") in pythonpath.split(":")
    assert str(vector_tbe) in pythonpath.split(":")
    assert str(toolkit_home / "python" / "site-packages") in env_detector.sys.path
    assert env_detector.os.environ.get("ASCEND_RUNTIME_PATH") == str(runtime_dir)
    assert env_detector.os.environ.get("ASCEND_OPP_PATH") == str(opp_dir)


def test_init_ascend_pythonpath_no_hardware_noop(monkeypatch) -> None:
    monkeypatch.setattr(env_detector.shutil, "which", lambda _cmd: None)
    monkeypatch.setenv("PYTHONPATH", "/keep/me")

    env_detector.EnvInitializer.init_ascend_pythonpath()

    assert env_detector.os.environ.get("PYTHONPATH") == "/keep/me"


def test_iter_ascend_toolkit_homes_prefers_complete_over_latest(monkeypatch, tmp_path) -> None:
    toolkit_root = tmp_path / "usr" / "local" / "Ascend" / "ascend-toolkit"
    latest = toolkit_root / "latest"
    versioned = toolkit_root / "8.0.RC3"

    # Incomplete latest: no hccl/lib64
    (latest / "runtime").mkdir(parents=True)
    (latest / "opp").mkdir(parents=True)
    (latest / "lib64").mkdir(parents=True)
    (latest / "fwkacllib" / "lib64").mkdir(parents=True)

    # Complete versioned toolkit
    (versioned / "runtime").mkdir(parents=True)
    (versioned / "opp").mkdir(parents=True)
    (versioned / "lib64").mkdir(parents=True)
    (versioned / "fwkacllib" / "lib64").mkdir(parents=True)
    (versioned / "hccl" / "lib64").mkdir(parents=True)

    real_path_cls = env_detector.Path

    def _fake_path(path):
        if str(path) == "/usr/local/Ascend/ascend-toolkit":
            return real_path_cls(str(toolkit_root))
        return real_path_cls(path)

    monkeypatch.setattr(env_detector, "Path", _fake_path)
    monkeypatch.delenv("ASCEND_HOME", raising=False)
    monkeypatch.delenv("ASCEND_HOME_PATH", raising=False)
    monkeypatch.delenv("ASCEND_RUNTIME_PATH", raising=False)

    homes = env_detector._iter_ascend_toolkit_homes()

    assert homes
    assert homes[0] == versioned


def test_preload_ascend_shared_libraries_uses_arch_hccl(monkeypatch, tmp_path) -> None:
    toolkit_home = tmp_path / "ascend-toolkit" / "8.0.RC3"
    lib_path = toolkit_home / "aarch64-linux" / "lib64" / "libhccl.so"
    lib_path.parent.mkdir(parents=True)
    lib_path.write_bytes(b"\x7fELF")

    calls: list[str] = []

    class _DummyCtypes:
        RTLD_GLOBAL = 0

        @staticmethod
        def CDLL(path: str, mode: int = 0):
            calls.append(path)
            return object()

    monkeypatch.setattr(env_detector, "ctypes", _DummyCtypes)

    env_detector._preload_ascend_shared_libraries(toolkit_home)

    assert calls == [str(lib_path)]
