from __future__ import annotations

import os
from pathlib import Path
import unittest

import numpy as np

from ap1_m1_boundary_match import (
    BoundaryMatchError,
    MatchPilotConfig,
    audit_authorities,
    build_match_pilot_report,
    friedmann_matched_physical_N,
    interpolate_sign_change_roots,
    select_latest_positive_frequency_root,
)
from ap1_r2c_self_consistent_candidate import standard_stress
from planck2018_neutrino_closure import Planck2018Pilot


APEIRON_ROOT = Path(os.environ["APEIRON_AP1_ROOT"])


class AP1M1BoundaryMatchTests(unittest.TestCase):
    def test_authority_hashes_are_exact(self):
        observed = audit_authorities(APEIRON_ROOT)
        self.assertEqual(len(observed), 9)

    def test_config_rejects_nonincreasing_levels(self):
        with self.assertRaises(ValueError):
            MatchPilotConfig(levels=(257, 257)).validate(15361)

    def test_config_rejects_insufficient_precision(self):
        with self.assertRaises(ValueError):
            MatchPilotConfig(levels=(257,), decimal_digits=31).validate(15361)

    def test_friedmann_density_inversion_reproduces_shared_background(self):
        pilot = Planck2018Pilot()
        target_N = -60.0
        target, _pressure = standard_stress(np.array([target_N]), pilot)
        recovered = friedmann_matched_physical_N(float(target[0]), pilot)
        self.assertAlmostEqual(recovered, target_N, places=11)

    def test_friedmann_density_inversion_rejects_nonpositive_allowance(self):
        with self.assertRaises(BoundaryMatchError):
            friedmann_matched_physical_N(0.0, Planck2018Pilot())

    def test_sign_change_interpolation_is_independent_of_absolute_scale(self):
        N = np.array([0.0, 1.0, 2.0])
        roots = interpolate_sign_change_roots(
            N,
            np.array([-60.0, -59.0, -58.0]),
            np.array([-2.0e-20, 2.0e-20, 4.0e-20]),
            np.array([-0.5, 0.5, 1.0]),
            np.array([3.0, 1.0, -1.0]),
            np.array([2.0, 1.0, 0.5]),
            np.array([8.0, 4.0, 2.0]),
        )
        self.assertEqual(len(roots), 1)
        self.assertEqual(roots[0]["N_local"], 0.5)
        self.assertEqual(roots[0]["N_physical"], -59.5)
        self.assertTrue(roots[0]["positive_vacuum_frequency_margin"])

    def test_selection_uses_latest_positive_frequency_root(self):
        roots = [
            {"N_local": 0.1, "positive_vacuum_frequency_margin": True},
            {"N_local": 0.2, "positive_vacuum_frequency_margin": True},
            {"N_local": 0.3, "positive_vacuum_frequency_margin": False},
        ]
        selected = select_latest_positive_frequency_root(roots)
        self.assertEqual(selected["N_local"], 0.2)

    def test_reduced_real_pilot_finds_simultaneous_bracket_but_releases_no_seed(self):
        report = build_match_pilot_report(
            APEIRON_ROOT,
            MatchPilotConfig(levels=(129,), mode_nodes=8, decimal_digits=60),
        )
        self.assertTrue(report["all_structural_pilot_gates_pass"])
        self.assertGreater(
            report["levels"][0]["simultaneous_sign_change_brackets"], 0
        )
        self.assertFalse(report["matching_tolerances_frozen"])
        self.assertEqual(
            report["selected_candidate_status"],
            "PILOT_ONLY_NOT_A_CHECKPOINT_OR_SEED",
        )
        self.assertFalse(report["new_AP1_M1_background_started"])
        self.assertFalse(report["physical_response_kernel_started"])

    def test_report_preserves_frozen_scientific_boundaries(self):
        report = build_match_pilot_report(
            APEIRON_ROOT,
            MatchPilotConfig(levels=(129,), mode_nodes=8, decimal_digits=60),
        )
        self.assertFalse(report["equations_changed"])
        self.assertFalse(report["physics_changed"])
        self.assertFalse(report["parameters_changed"])
        self.assertFalse(report["existing_gate_thresholds_changed"])
        self.assertFalse(report["nonpass_stored_or_used_as_seed"])


if __name__ == "__main__":
    unittest.main()
