"""Tests for comparison strategies."""
from abi_evals.comparators import (
    compare_exact,
    compare_golden_exact,
    compare_golden_structural,
    compare_numeric_tolerance,
    compare_presence_assert,
    compare_regex_assert,
    compare_schema_validate,
)


class TestExact:
    def test_match(self):
        ok, _ = compare_exact("hello", "hello")
        assert ok

    def test_no_match(self):
        ok, _ = compare_exact("hello", "world")
        assert not ok

    def test_numeric_match(self):
        ok, _ = compare_exact(42, 42)
        assert ok


class TestGoldenExact:
    def test_match(self):
        ok, _ = compare_golden_exact({"a": 1}, {"a": 1})
        assert ok

    def test_no_match(self):
        ok, _ = compare_golden_exact({"a": 1}, {"a": 2})
        assert not ok

    def test_key_order_insensitive(self):
        ok, _ = compare_golden_exact({"b": 2, "a": 1}, {"a": 1, "b": 2})
        assert ok  # sort_keys=True makes them equal


class TestGoldenStructural:
    def test_match(self):
        ok, _ = compare_golden_structural({"a": 1, "b": 2}, {"a": 1, "b": 2})
        assert ok

    def test_extra_keys_ok(self):
        ok, _ = compare_golden_structural({"a": 1, "b": 2, "c": 3}, {"a": 1, "b": 2})
        assert ok  # actual has extra key, but expected keys all present

    def test_missing_key(self):
        ok, _ = compare_golden_structural({"a": 1}, {"a": 1, "b": 2})
        assert not ok


class TestNumericTolerance:
    def test_within_tolerance(self):
        ok, _ = compare_numeric_tolerance(3.14159, 3.14160, 0.001)
        assert ok

    def test_outside_tolerance(self):
        ok, _ = compare_numeric_tolerance(3.14, 3.20, 0.001)
        assert not ok

    def test_nan_match(self):
        ok, _ = compare_numeric_tolerance(float("nan"), float("nan"), 0.001)
        assert ok

    def test_nested(self):
        ok, _ = compare_numeric_tolerance(
            {"val": 1.001}, {"val": 1.002}, 0.01
        )
        assert ok


class TestRegexAssert:
    def test_single_pattern(self):
        ok, _ = compare_regex_assert("The result is 42", "\\d+")
        assert ok

    def test_multiple_patterns(self):
        ok, _ = compare_regex_assert("The result is 42 items", ["\\d+", "items$"])
        assert ok

    def test_pattern_not_found(self):
        ok, _ = compare_regex_assert("no numbers here", ["\\d+"])
        assert not ok


class TestPresenceAssert:
    def test_all_present(self):
        ok, _ = compare_presence_assert({"a": 1, "b": 2}, ["a", "b"])
        assert ok

    def test_missing(self):
        ok, _ = compare_presence_assert({"a": 1}, ["a", "b"])
        assert not ok

    def test_list_input(self):
        ok, _ = compare_presence_assert(["manifest", "events"], ["manifest"])
        assert ok


class TestSchemaValidate:
    def test_required_keys_present(self):
        ok, _ = compare_schema_validate(
            {"schema_version": "test/1.0", "run_id": "abc"},
            {"$required_keys": ["schema_version", "run_id"]},
        )
        assert ok

    def test_required_keys_missing(self):
        ok, _ = compare_schema_validate(
            {"schema_version": "test/1.0"},
            {"$required_keys": ["schema_version", "run_id"]},
        )
        assert not ok
