from __future__ import annotations

import importlib

import numpy as np
import pytest


def _cython_ext_available() -> bool:
    try:
        importlib.import_module("zen_fronts.pareto_core._pareto_rating_cy")
        return True
    except Exception:
        return False


@pytest.mark.skipif(
    not _cython_ext_available(),
    reason="Cython extension is not built (zen_fronts.pareto_core._pareto_rating_cy)",
)
def test_rate_population_inplace_debug_matches_public_arrays() -> None:
    from zen_fronts.pareto_core._pareto_rating_cy import (  # type: ignore
        _rate_population_inplace_debug,
        rate_population_arrays_cy,
    )

    rng = np.random.default_rng(0)

    for mode_i in (0, 1):
        X = rng.random((64, 4), dtype=np.float64)

        out_dbg = _rate_population_inplace_debug(X, mode_i, 0)
        out_pub = rate_population_arrays_cy(X, mode_i, 0)

        # Required: exact equality for discrete outputs and tight numeric match.
        f_dbg, w_dbg, o_dbg, off_dbg, items_dbg = out_dbg
        f_pub, w_pub, o_pub, off_pub, items_pub = out_pub

        assert np.array_equal(f_dbg, f_pub)
        assert np.array_equal(o_dbg, o_pub)

        assert np.array_equal(off_dbg, off_pub)
        assert np.array_equal(items_dbg, items_pub)

        # within_score: inf positions must match; finite must match tightly
        inf_dbg = np.isinf(w_dbg)
        inf_pub = np.isinf(w_pub)
        assert np.array_equal(inf_dbg, inf_pub)

        finite = ~inf_dbg
        assert np.allclose(w_dbg[finite], w_pub[finite], rtol=0.0, atol=1e-12)
