"""Tests for optimizer module helpers: snap_to_preferred, format_engineering."""

import pytest

from mcltspice.optimizer import format_engineering, snap_to_preferred


class TestSnapToPreferred:
    def test_e12_exact_match(self):
        """A value that is already an E12 value should snap to itself."""
        assert snap_to_preferred(4700.0, "E12") == pytest.approx(4700.0, rel=0.01)

    def test_e12_near_value(self):
        """4800 should snap to 4700 (E12)."""
        result = snap_to_preferred(4800.0, "E12")
        assert result == pytest.approx(4700.0, rel=0.05)

    def test_e24_finer_resolution(self):
        """E24 has 5.1, so 5050 should snap to 5100."""
        result = snap_to_preferred(5050.0, "E24")
        assert result == pytest.approx(5100.0, rel=0.05)

    def test_e96_precision(self):
        """E96 should snap to a value very close to the input."""
        result = snap_to_preferred(4750.0, "E96")
        assert result == pytest.approx(4750.0, rel=0.03)

    def test_zero_value(self):
        """Zero should snap to the smallest E-series value."""
        result = snap_to_preferred(0.0, "E12")
        assert result > 0

    def test_negative_value(self):
        """Negative value should snap to the smallest E-series value."""
        result = snap_to_preferred(-100.0, "E12")
        assert result > 0

    def test_sub_ohm(self):
        """Small values (e.g., 0.47 ohms) should snap correctly."""
        result = snap_to_preferred(0.5, "E12")
        assert result == pytest.approx(0.47, rel=0.1)

    def test_megohm_range(self):
        """Large values should snap correctly across decades."""
        result = snap_to_preferred(2_200_000.0, "E12")
        assert result == pytest.approx(2_200_000.0, rel=0.05)

    def test_unknown_series_defaults_to_e12(self):
        """Unknown series name should fall back to E12."""
        result = snap_to_preferred(4800.0, "E6")
        assert result == pytest.approx(4700.0, rel=0.05)


class TestFormatEngineering:
    def test_10k(self):
        assert format_engineering(10_000) == "10k"

    def test_1u(self):
        assert format_engineering(0.000001) == "1u"

    def test_4_7k(self):
        assert format_engineering(4700) == "4.7k"

    def test_zero(self):
        assert format_engineering(0) == "0"

    def test_1_5(self):
        """Values in the unity range should have no suffix."""
        result = format_engineering(1.5)
        assert result == "1.5"

    def test_negative(self):
        result = format_engineering(-4700)
        assert result.startswith("-")
        assert "4.7k" in result

    def test_picofarad(self):
        result = format_engineering(100e-12)
        assert "100p" in result

    def test_milliamp(self):
        result = format_engineering(0.010)
        assert "10m" in result

    def test_large_value(self):
        result = format_engineering(1e9)
        assert "G" in result or "1e" in result
