"""Tests for TEME <-> ECEF coordinate conversions."""

import numpy as np
import pytest

from gri_utils.conversion import ecef_to_teme, teme_to_ecef

# Test point: equator on prime meridian at equatorial radius
_XYZ_EQUATOR = np.array([6378137.0, 0.0, 0.0])


def test_ecef_to_teme_at_unix_epoch() -> None:
    """Test ECEF to TEME conversion at Unix epoch."""
    teme = ecef_to_teme(_XYZ_EQUATOR, 0.0)
    # At Unix epoch, GMST is non-zero, so ECEF and TEME differ
    assert teme.shape == (3,)
    # The z-component should be unchanged (rotation is about z-axis)
    assert teme[2] == pytest.approx(_XYZ_EQUATOR[2], rel=1e-10)
    # The magnitude should be preserved
    assert np.linalg.norm(teme) == pytest.approx(
        np.linalg.norm(_XYZ_EQUATOR),
        rel=1e-10,
    )


def test_teme_to_ecef_at_unix_epoch() -> None:
    """Test TEME to ECEF conversion at Unix epoch."""
    ecef = teme_to_ecef(_XYZ_EQUATOR, 0.0)
    assert ecef.shape == (3,)
    # The z-component should be unchanged
    assert ecef[2] == pytest.approx(_XYZ_EQUATOR[2], rel=1e-10)
    # The magnitude should be preserved
    assert np.linalg.norm(ecef) == pytest.approx(
        np.linalg.norm(_XYZ_EQUATOR),
        rel=1e-10,
    )


def test_round_trip_ecef_teme_ecef() -> None:
    """Test round-trip conversion ECEF -> TEME -> ECEF."""
    time = 1704067200.0  # 2024-01-01 00:00:00 UTC
    original = np.array([6778000.0, 1234567.0, 2345678.0])

    teme = ecef_to_teme(original, time)
    recovered = teme_to_ecef(teme, time)

    np.testing.assert_allclose(recovered, original, rtol=1e-10)


def test_round_trip_teme_ecef_teme() -> None:
    """Test round-trip conversion TEME -> ECEF -> TEME."""
    time = 1704067200.0
    original = np.array([7000000.0, 500000.0, 3000000.0])

    ecef = teme_to_ecef(original, time)
    recovered = ecef_to_teme(ecef, time)

    np.testing.assert_allclose(recovered, original, rtol=1e-10)


def test_ecef_teme_polar_point() -> None:
    """Test that polar points (on z-axis) are unchanged."""
    polar_point = np.array([0.0, 0.0, 6356752.0])  # At polar radius
    time = 1234567890.0

    teme = ecef_to_teme(polar_point, time)
    np.testing.assert_allclose(teme, polar_point, rtol=1e-10)

    ecef = teme_to_ecef(polar_point, time)
    np.testing.assert_allclose(ecef, polar_point, rtol=1e-10)


def test_batch_conversion() -> None:
    """Test conversion of multiple points with corresponding times."""
    points = np.array(
        [
            [6378137.0, 0.0, 0.0],
            [0.0, 6378137.0, 0.0],
            [4500000.0, 4500000.0, 0.0],
        ],
    )
    times = np.array([0.0, 3600.0, 7200.0])

    # Convert batch
    teme_batch = ecef_to_teme(points, times)
    assert teme_batch.shape == (3, 3)

    # Round-trip each point
    ecef_recovered = teme_to_ecef(teme_batch, times)
    np.testing.assert_allclose(ecef_recovered, points, rtol=1e-9, atol=1e-9)


def test_single_time_multiple_points() -> None:
    """Test multiple points at a single time."""
    points = np.array(
        [
            [6378137.0, 0.0, 0.0],
            [0.0, 6378137.0, 0.0],
        ],
    )
    time = 1704067200.0

    teme = ecef_to_teme(points, time)
    assert teme.shape == (2, 3)

    # All points rotated by same angle
    ecef_recovered = teme_to_ecef(teme, time)
    np.testing.assert_allclose(ecef_recovered, points, rtol=1e-10)


def test_sequence_input() -> None:
    """Test that sequence inputs (lists, tuples) work."""
    point_list = [6378137.0, 1000000.0, 2000000.0]
    point_tuple = (6378137.0, 1000000.0, 2000000.0)

    time = 1704067200.0

    teme_from_list = ecef_to_teme(point_list, time)
    teme_from_tuple = ecef_to_teme(point_tuple, time)

    np.testing.assert_allclose(teme_from_list, teme_from_tuple, rtol=1e-15)
