"""Tests for diagnostics module."""

import numpy as np
import pytest


class TestCornerArcLen:
    """Tests for corner arc length computation.

    Note: The panel discretization requires beta < n to avoid degenerate panels.
    Using n=16 (p=32) with beta=4.0 for stable results.
    """

    def test_corner_arc_len_once_returns_tuple(self):
        """Should return (arc_len, u0, dof)."""
        from harmonic_measure.diagnostics import corner_arc_len_once

        arc, u0, dof = corner_arc_len_once(
            n=16, a=1.0, c=2.0,
            beta=4.0, panels_per_quadrant=4, m_per_panel=8
        )

        assert isinstance(arc, float)
        assert isinstance(u0, float)
        assert isinstance(dof, int)
        assert arc > 0
        assert u0 > 0
        assert dof > 0

    def test_arc_len_decreases_with_n(self):
        """Arc length should decrease as n increases."""
        from harmonic_measure.diagnostics import corner_arc_len_once

        arc16, _, _ = corner_arc_len_once(
            n=16, a=1.0, c=2.0,
            beta=4.0, panels_per_quadrant=4, m_per_panel=8
        )

        arc32, _, _ = corner_arc_len_once(
            n=32, a=1.0, c=2.0,
            beta=4.0, panels_per_quadrant=4, m_per_panel=8
        )

        assert arc16 > arc32

    def test_dof_scales_with_discretization(self):
        """DOF should scale with panels and nodes."""
        from harmonic_measure.diagnostics import corner_arc_len_once

        _, _, dof1 = corner_arc_len_once(
            n=16, a=1.0, c=2.0,
            beta=4.0, panels_per_quadrant=2, m_per_panel=8
        )

        _, _, dof2 = corner_arc_len_once(
            n=16, a=1.0, c=2.0,
            beta=4.0, panels_per_quadrant=4, m_per_panel=8
        )

        # Doubling panels should approximately double DOF
        assert dof2 > dof1
        assert dof2 == pytest.approx(2 * dof1, rel=0.1)


class TestConvergedComputation:
    """Tests for adaptive convergence."""

    def test_convergence_returns_all_outputs(self):
        """Should return arc, u0, params, history."""
        from harmonic_measure.diagnostics import corner_arc_len_converged

        arc, u0, params, history = corner_arc_len_converged(
            n=16, a=1.0, c=2.0,
            quality="fast",
            max_rounds=2,
            verbose=False,
        )

        assert isinstance(arc, float)
        assert isinstance(u0, float)
        assert isinstance(params, dict)
        assert isinstance(history, list)

    def test_history_records_refinement(self):
        """History should contain refinement records."""
        from harmonic_measure.diagnostics import corner_arc_len_converged

        _, _, _, history = corner_arc_len_converged(
            n=16, a=1.0, c=2.0,
            quality="fast",
            max_rounds=2,
            verbose=False,
        )

        # Should have at least one entry
        assert len(history) >= 1

        # Each entry should have expected fields
        for record in history:
            assert hasattr(record, "arc_len")
            assert hasattr(record, "n_nodes")
            assert hasattr(record, "round")

    def test_params_contains_expected_keys(self):
        """Final params should contain expected keys."""
        from harmonic_measure.diagnostics import corner_arc_len_converged

        _, _, params, _ = corner_arc_len_converged(
            n=16, a=1.0, c=2.0,
            quality="fast",
            max_rounds=2,
            verbose=False,
        )

        assert "panels_per_quadrant" in params
        assert "m_per_panel" in params
        assert "beta" in params

    def test_quality_levels(self):
        """Different quality levels should work."""
        from harmonic_measure.diagnostics import corner_arc_len_converged

        # Fast should complete quickly
        arc_fast, _, _, hist_fast = corner_arc_len_converged(
            n=16, a=1.0, c=2.0,
            quality="fast",
            max_rounds=2,
            verbose=False,
        )

        # Both should return valid results
        assert arc_fast > 0


class TestAdaptiveConvergence:
    """Tests for the adaptive_convergence wrapper."""

    def test_returns_arc_and_history(self):
        """Should return arc length and history."""
        from harmonic_measure.diagnostics import adaptive_convergence

        arc, history = adaptive_convergence(
            n=16, a=1.0, c=2.0,
            tol=1e-2,  # Looser tolerance for speed
            verbose=False,
        )

        assert isinstance(arc, float)
        assert isinstance(history, list)
        assert arc > 0
        assert len(history) >= 1


class TestScalingDiagnostic:
    """Tests for scaling law diagnostic."""

    def test_scaling_returns_slope(self):
        """Should return ns, arcs, and fitted slope."""
        from harmonic_measure.diagnostics import corner_scaling_diagnostic

        ns = [16, 32]  # Higher n for stable discretization
        ns_out, arcs, slope = corner_scaling_diagnostic(
            ns, a=1.0, c=2.0,
            tol=1e-2,  # Looser tolerance for speed
        )

        assert len(ns_out) == len(ns)
        assert len(arcs) == len(ns)
        assert isinstance(slope, float)

    def test_slope_negative(self):
        """Fitted slope should be negative."""
        from harmonic_measure.diagnostics import corner_scaling_diagnostic

        ns = [16, 32]
        _, _, slope = corner_scaling_diagnostic(
            ns, a=1.0, c=2.0,
            tol=1e-2,
        )

        # Should be negative (decreasing)
        assert slope < 0

    def test_arcs_decrease(self):
        """Arc lengths should decrease with n."""
        from harmonic_measure.diagnostics import corner_scaling_diagnostic

        ns = [16, 32]
        _, arcs, _ = corner_scaling_diagnostic(
            ns, a=1.0, c=2.0,
            tol=1e-2,
        )

        assert arcs[0] > arcs[1]


class TestRefinementRecord:
    """Tests for RefinementRecord dataclass."""

    def test_record_fields(self):
        """Record should have all expected fields."""
        from harmonic_measure.diagnostics import RefinementRecord

        record = RefinementRecord(
            round=1,
            panels_per_quadrant=4,
            m_per_panel=8,
            beta=8.0,
            n_nodes=128,
            arc_len=0.123,
        )

        assert record.round == 1
        assert record.panels_per_quadrant == 4
        assert record.m_per_panel == 8
        assert record.beta == 8.0
        assert record.n_nodes == 128
        assert record.arc_len == 0.123
        assert record.delta_abs is None
        assert record.delta_rel is None

    def test_record_with_deltas(self):
        """Record should accept delta values."""
        from harmonic_measure.diagnostics import RefinementRecord

        record = RefinementRecord(
            round=2,
            panels_per_quadrant=4,
            m_per_panel=8,
            beta=8.0,
            n_nodes=128,
            arc_len=0.123,
            delta_abs=0.001,
            delta_rel=0.01,
        )

        assert record.delta_abs == 0.001
        assert record.delta_rel == 0.01
