"""Phase 1 — Determinism hardening tests for abi-evals.

Verifies that:
- Eval results have identical SHA-256 hashes for identical inputs
- Comparator outputs are deterministic
- Golden serialization is byte-stable
"""

from __future__ import annotations

import hashlib
import json

from abi_evals.comparators import (
    compare_exact,
    compare_golden_exact,
    compare_golden_structural,
    compare_numeric_tolerance,
)
from abi_evals.runner import run_suite, write_results


def _sha256(data: str) -> str:
    return hashlib.sha256(data.encode()).hexdigest()


class TestEvalResultHashStability:
    """Same suite + same run_id + same timestamp => same SHA-256."""

    def test_result_hash_identical(self, sample_suite):
        r1 = run_suite(sample_suite, run_id="h0000001", timestamp="2025-01-01T00:00:00Z")
        r2 = run_suite(sample_suite, run_id="h0000001", timestamp="2025-01-01T00:00:00Z")
        s1 = json.dumps(r1, sort_keys=True)
        s2 = json.dumps(r2, sort_keys=True)
        assert _sha256(s1) == _sha256(s2), "Eval result hash mismatch"

    def test_result_file_byte_identical(self, sample_suite, tmp_path):
        r = run_suite(sample_suite, run_id="h0000002", timestamp="2025-01-01T00:00:00Z")
        p1 = tmp_path / "r1.json"
        p2 = tmp_path / "r2.json"
        write_results(r, p1)
        write_results(r, p2)
        assert p1.read_bytes() == p2.read_bytes()


class TestComparatorDeterminism:
    """Each comparator returns identical results for identical inputs."""

    def test_exact_stable(self):
        for _ in range(10):
            ok, msg = compare_exact("hello", "hello")
            assert ok is True

    def test_golden_exact_stable(self):
        d = {"key": "value", "num": 42}
        results = set()
        for _ in range(10):
            ok, msg = compare_golden_exact(d, d)
            results.add(ok)
        assert results == {True}

    def test_structural_stable(self):
        a = {"x": 1, "y": "hello"}
        b = {"x": 1, "y": "hello"}
        for _ in range(10):
            ok, msg = compare_golden_structural(a, b)
            assert ok is True

    def test_numeric_tolerance_stable(self):
        for _ in range(10):
            ok, msg = compare_numeric_tolerance(3.14159, 3.14159, 1e-6)
            assert ok is True


class TestJsonSerializationStability:
    """JSON output uses sort_keys for deterministic ordering."""

    def test_unordered_dict_sorted(self):
        d1 = {"z": 3, "a": 1, "m": 2}
        d2 = {"a": 1, "m": 2, "z": 3}
        assert json.dumps(d1, sort_keys=True) == json.dumps(d2, sort_keys=True)

    def test_nested_dict_sorted(self):
        d = {"outer": {"z_inner": 1, "a_inner": 2}}
        s1 = json.dumps(d, sort_keys=True)
        s2 = json.dumps(d, sort_keys=True)
        assert _sha256(s1) == _sha256(s2)
