"""Tests for from_tle (TLE parsing)."""

import math

import pytest

from gri_utils.orbit import from_tle

# ISS (ZARYA) TLE from CelesTrak
_ISS_LINE1 = "1 25544U 98067A   24001.50000000  .00016717  00000-0  10270-3 0  9993"
_ISS_LINE2 = "2 25544  51.6400  10.5000 0001234  90.0000 270.0000 15.49500000000000"

# Highly elliptical orbit (Molniya-like)
_MOLNIYA_LINE1 = "1 99999U 00000A   24001.00000000  .00000000  00000-0  00000-0 0  0000"
_MOLNIYA_LINE2 = "2 99999  63.4000  45.0000 7000000 270.0000   0.0000  2.00600000000000"


def test_iss_inclination() -> None:
    """Test parsing ISS TLE returns correct inclination."""
    elements = from_tle(_ISS_LINE1, _ISS_LINE2)

    expected_inclination = math.radians(51.64)
    assert elements.inclination_rad == pytest.approx(expected_inclination, rel=1e-4)


def test_iss_raan() -> None:
    """Test parsing ISS TLE returns correct RAAN."""
    elements = from_tle(_ISS_LINE1, _ISS_LINE2)

    expected_raan = math.radians(10.5)
    assert elements.raan_rad == pytest.approx(expected_raan, rel=1e-4)


def test_iss_eccentricity() -> None:
    """Test parsing ISS TLE returns correct eccentricity."""
    elements = from_tle(_ISS_LINE1, _ISS_LINE2)

    # ISS eccentricity is 0.0001234 (implied decimal)
    expected_eccentricity = 0.0001234
    assert elements.eccentricity == pytest.approx(expected_eccentricity, rel=1e-4)


def test_iss_mean_anomaly() -> None:
    """Test parsing ISS TLE returns correct mean anomaly."""
    elements = from_tle(_ISS_LINE1, _ISS_LINE2)

    expected_mean_anomaly = math.radians(270.0)
    assert elements.mean_anomaly_rad == pytest.approx(expected_mean_anomaly, rel=1e-4)


def test_iss_arg_periapsis() -> None:
    """Test parsing ISS TLE returns correct argument of periapsis."""
    elements = from_tle(_ISS_LINE1, _ISS_LINE2)

    expected_arg_periapsis = math.radians(90.0)
    assert elements.arg_periapsis_rad == pytest.approx(expected_arg_periapsis, rel=1e-4)


def test_iss_semi_major_axis() -> None:
    """Test that ISS semi-major axis is computed correctly from mean motion."""
    elements = from_tle(_ISS_LINE1, _ISS_LINE2)

    # ISS orbits at ~400 km altitude, so a ≈ 6778 km
    # More precisely, with n = 15.495 rev/day:
    # a = (mu / n^2)^(1/3)
    assert 6_700_000 < elements.semi_major_axis_m < 6_900_000


def test_iss_epoch() -> None:
    """Test that ISS TLE epoch is parsed correctly."""
    elements = from_tle(_ISS_LINE1, _ISS_LINE2)

    # Epoch is 24001.5 = 2024, day 1.5 (Jan 1, 12:00 UTC)
    # Jan 1, 2024 12:00 UTC = 1704110400.0
    expected_epoch = 1704110400.0
    assert elements.epoch_unix_s == pytest.approx(expected_epoch, rel=1e-6)


def test_elliptical_orbit_eccentricity() -> None:
    """Test parsing of highly elliptical orbit."""
    elements = from_tle(_MOLNIYA_LINE1, _MOLNIYA_LINE2)

    # Eccentricity is 0.7 (7000000 with implied decimal)
    expected_e = 0.7
    assert elements.eccentricity == pytest.approx(expected_e, rel=1e-6)


def test_invalid_line1_raises() -> None:
    """Test that invalid line 1 raises ValueError."""
    bad_line1 = "2 25544U 98067A   24001.50000000"  # Starts with 2
    with pytest.raises(ValueError, match="Line 1"):
        from_tle(bad_line1, _ISS_LINE2)


def test_invalid_line2_raises() -> None:
    """Test that invalid line 2 raises ValueError."""
    bad_line2 = "1 25544  51.6400  10.5000"  # Starts with 1
    with pytest.raises(ValueError, match="Line 2"):
        from_tle(_ISS_LINE1, bad_line2)


def test_short_line1_raises() -> None:
    """Test that too-short line 1 raises ValueError."""
    short_line = "1 25544U 98067A"
    with pytest.raises(ValueError, match="too short"):
        from_tle(short_line, _ISS_LINE2)


def test_short_line2_raises() -> None:
    """Test that too-short line 2 raises ValueError."""
    short_line = "2 25544  51.6400"
    with pytest.raises(ValueError, match="too short"):
        from_tle(_ISS_LINE1, short_line)


def test_whitespace_handling() -> None:
    """Test that lines with extra whitespace are handled."""
    line1_padded = "  " + _ISS_LINE1 + "  "
    line2_padded = "  " + _ISS_LINE2 + "  "

    elements = from_tle(line1_padded, line2_padded)

    # Should parse successfully
    assert elements.eccentricity == pytest.approx(0.0001234, rel=1e-4)


def test_epoch_year_2000s() -> None:
    """Test epoch parsing for year 2000-2056 (YY < 57)."""
    # Year 24 = 2024
    elements = from_tle(_ISS_LINE1, _ISS_LINE2)

    # Should be in 2024 (Unix timestamp > 2024-01-01)
    jan_2024 = 1704067200.0  # 2024-01-01 00:00:00 UTC
    assert elements.epoch_unix_s > jan_2024


def test_real_tle_starlink() -> None:
    """Test with a real Starlink TLE."""
    # STARLINK-30301 from CelesTrak
    line1 = "1 56988U 23084A   24001.91667824  .00001234  00000-0  12345-4 0  9999"
    line2 = "2 56988  53.2176 123.4567 0001234  98.7654 261.2345 15.05123456789012"

    elements = from_tle(line1, line2)

    # Starlink inclination is ~53 degrees
    assert math.degrees(elements.inclination_rad) == pytest.approx(53.2176, rel=1e-4)

    # Starlink orbits at ~550 km altitude
    assert 6_800_000 < elements.semi_major_axis_m < 7_000_000
