"""Tests for LSCCurve parameter validation functionality."""

from __future__ import annotations

import pytest
from _pytest.logging import LogCaptureFixture

from pytola_sim.lscopt.cli import LSCCurve


class TestLSCCurveValidation:
    """Tests for LSCCurve parameter validation."""

    def test_valid_parameters(self) -> None:
        """Test that valid parameters work correctly."""
        # Should not raise any exceptions
        curve = LSCCurve()
        assert curve.m == pytest.approx(-1.3)
        assert curve.m1 == pytest.approx(-2.4)

    def test_invalid_angle_parameters(self) -> None:
        """Test validation of angle parameters."""
        # Test invalid J values
        with pytest.raises(ValueError, match="Overall angle J must be between 0 and 180"):
            LSCCurve(J=-10)

        with pytest.raises(ValueError, match="Overall angle J must be between 0 and 180"):
            LSCCurve(J=200)

        # Test invalid J1 values
        with pytest.raises(ValueError, match="Internal angle J1 must be between 0 and 180"):
            LSCCurve(J1=-5)

        with pytest.raises(ValueError, match="Internal angle J1 must be between 0 and 180"):
            LSCCurve(J1=190)

    def test_invalid_breakpoint_parameters(self) -> None:
        """Test validation of breakpoint parameters."""
        # Test positive m values
        with pytest.raises(ValueError, match="Internal breakpoint m must be negative"):
            LSCCurve(m=1.0)

        # Test positive m1 values
        with pytest.raises(ValueError, match="External breakpoint m1 must be negative"):
            LSCCurve(m1=0.5)

        # Test incorrect breakpoint ordering
        with pytest.raises(ValueError, match="must be less than internal breakpoint"):
            LSCCurve(m=-1.0, m1=-0.5)  # m1 should be more negative than m

    def test_warning_conditions(self, caplog: LogCaptureFixture) -> None:
        """Test that warning conditions produce appropriate log messages."""
        import logging

        from pytola_sim.lscopt.cli import logger as lscopt_logger

        caplog.set_level(logging.WARNING)
        # Ensure the logger is properly configured for testing
        lscopt_logger.setLevel(logging.WARNING)
        lscopt_logger.addHandler(caplog.handler)

        # Test negative height parameters (should produce warnings)
        LSCCurve(H=-0.1, H1=-0.05, H2=-0.15)
        assert "Negative cutting height H=-0.1 may lead to unexpected results" in caplog.text
        assert "Negative internal retention height H1=-0.05 may lead to unexpected results" in caplog.text
        assert "Negative external retention height H2=-0.15 may lead to unexpected results" in caplog.text

        # Test negative slope parameters (should produce warnings)
        caplog.clear()
        lscopt_logger.removeHandler(caplog.handler)  # Remove previous handler
        lscopt_logger.addHandler(caplog.handler)  # Add new handler
        LSCCurve(s=-1.0, s1=-2.0)
        assert "Negative internal slope s=-1.0 may lead to unexpected results" in caplog.text
        assert "Negative external slope s1=-2.0 may lead to unexpected results" in caplog.text

    def test_boundary_conditions(self) -> None:
        """Test boundary conditions for parameters."""
        # Test edge case: zero angles
        curve = LSCCurve(J=0, J1=0)
        assert curve.J == 0
        assert curve.J1 == 0

        # Test edge case: maximum angles
        curve = LSCCurve(J=180, J1=180)
        assert curve.J == 180
        assert curve.J1 == 180

        # Test edge case: breakpoints at zero boundary
        with pytest.raises(ValueError, match="Internal breakpoint m must be negative"):
            LSCCurve(m=0)  # Should be negative

        with pytest.raises(ValueError, match="External breakpoint m1 must be negative"):
            LSCCurve(m1=0)  # Should be negative


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
