"""Regression tests for astronomical Galactic-longitude sky-map geometry."""

from __future__ import annotations

import matplotlib.pyplot as plt
import numpy as np
import pytest
from matplotlib.figure import Figure
from matplotlib.patches import Polygon

import generate_sky_coverage_figures as sky


def test_galactic_longitude_uses_left_increasing_astro_convention() -> None:
    projected = sky._galactic_longitude_to_mollweide_rad(
        np.array([0.0, 90.0, 120.0, 180.0, 220.0, 270.0, 360.0])
    )

    assert projected[0] == pytest.approx(0.0)
    assert projected[1] == pytest.approx(-np.pi / 2)
    assert projected[2] == pytest.approx(-np.deg2rad(120.0))
    assert abs(projected[3]) == pytest.approx(np.pi)
    assert projected[4] == pytest.approx(np.deg2rad(140.0))
    assert projected[5] == pytest.approx(np.pi / 2)
    assert projected[6] == pytest.approx(0.0)
    assert np.all(np.abs(projected) <= np.pi)
    assert sky._galactic_longitude_to_mollweide_rad(sky.M31_L_DEG) < 0


def test_longitude_labels_remain_in_zero_to_360_degree_notation() -> None:
    fig = plt.figure()
    ax = fig.add_subplot(111, projection="mollweide")
    sky._set_lon_labels(ax, fontsize=8)
    labels = {
        text.get_text(): text.get_position()[0]
        for text in ax.texts
        if text.get_text().startswith("l=")
    }
    plt.close(fig)

    assert labels["l=90°"] < 0
    assert labels["l=0°"] == pytest.approx(0.0)
    assert labels["l=270°"] > 0
    assert "l=-90°" not in labels
    assert "l=-180°" not in labels


def test_efeds_rectangle_is_visible_on_the_right_hand_sky() -> None:
    polygons = sky._galactic_rectangle_vertices(220.0, 235.0, 20.0, 40.0)

    assert len(polygons) == 1
    longitude_rad, latitude_rad = polygons[0]
    assert np.all((0 < longitude_rad) & (longitude_rad < np.pi))
    assert np.all(np.abs(latitude_rad) <= np.pi / 2)


def test_locatelli_map_places_eastern_exclusion_left_and_western_domain_right(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    captured: dict[str, Figure] = {}

    def capture(fig: Figure, stem: str, column: str) -> None:
        captured[f"{stem}_{column}"] = fig

    monkeypatch.setattr(sky, "_save", capture)
    sky.plot_locatelli_sky("2col", 7.0)
    fig = captured["locatelli_sky_coverage_2col"]
    ax = fig.axes[0]
    labelled = {patch.get_label(): patch for patch in ax.patches}

    western = labelled["eRASS1 western half (180<l<360°)"]
    eastern = labelled["Excluded eastern half (0<l<180°)"]
    assert isinstance(western, Polygon)
    assert isinstance(eastern, Polygon)
    assert np.all(np.asarray(western.get_xy())[:, 0] >= 0)
    assert np.all(np.asarray(eastern.get_xy())[:, 0] <= 0)
    plt.close(fig)


def test_ueda_rectangle_splits_at_l180_projection_seam() -> None:
    polygons = sky._galactic_rectangle_vertices(75.0, 285.0, 15.0, 90.0)

    assert len(polygons) == 2
    left_longitude, _ = polygons[0]
    right_longitude, _ = polygons[1]
    assert np.all(left_longitude <= 0)
    assert np.all(right_longitude >= 0)
    assert np.all(np.abs(np.concatenate([left_longitude, right_longitude])) <= np.pi)


def test_halosat_2020_catalog_is_exactly_73_southern_fields() -> None:
    fields = sky._load_halosat_2020_fields()

    assert len(fields) == 73
    assert fields["obsid"].nunique() == 73
    assert fields["galactic_b_deg"].max() == pytest.approx(-30.199)
    assert fields["galactic_b_deg"].min() == pytest.approx(-83.434)
    assert (fields["galactic_b_deg"] < -30).all()
    assert fields["galactic_l_deg"].between(0, 360, inclusive="left").all()


def test_halosat_map_separates_selection_envelope_from_73_centers(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    captured: dict[str, Figure] = {}

    def capture(fig: Figure, stem: str, column: str) -> None:
        captured[f"{stem}_{column}"] = fig

    monkeypatch.setattr(sky, "_save", capture)
    sky.plot_halosat_sky("2col", 7.0)
    fig = captured["halosat_sky_coverage_2col"]
    ax = fig.axes[0]
    labelled = {artist.get_label(): artist for artist in ax.collections}

    fitted = labelled["Kaaret+20 fitted field centers (N=73)"]
    assert np.asarray(fitted.get_offsets()).shape == (73, 2)
    assert "2020 selection envelope (b<-30°)" in labelled
    plt.close(fig)
