"""Tests for AWC METAR helper functions."""

from __future__ import annotations

from therminal.weather._awc import (
    celsius_to_f,
    icao_to_station_code,
    map_cloud_cover,
    parse_awc_visibility,
    station_to_icao,
)

# ===========================================================================
# parse_awc_visibility
# ===========================================================================


class TestParseAwcVisibility:
    """Tests 1-10: parse_awc_visibility."""

    def test_ten_plus(self) -> None:
        """1. '10+' -> 10.0."""
        assert parse_awc_visibility("10+") == 10.0

    def test_half(self) -> None:
        """2. '1/2' -> 0.5."""
        assert parse_awc_visibility("1/2") == 0.5

    def test_mixed_number(self) -> None:
        """3. '2 1/4' -> 2.25."""
        assert parse_awc_visibility("2 1/4") == 2.25

    def test_three_quarters(self) -> None:
        """4. '3/4' -> 0.75."""
        assert parse_awc_visibility("3/4") == 0.75

    def test_plain_number(self) -> None:
        """5. '10' -> 10.0."""
        assert parse_awc_visibility("10") == 10.0

    def test_none_returns_none(self) -> None:
        """6. None -> None."""
        assert parse_awc_visibility(None) is None

    def test_empty_string_returns_none(self) -> None:
        """7. '' -> None."""
        assert parse_awc_visibility("") is None

    def test_null_string_returns_none(self) -> None:
        """8. 'null' -> None."""
        assert parse_awc_visibility("null") is None

    def test_int_input(self) -> None:
        """9. 5 (int) -> 5.0."""
        assert parse_awc_visibility(5) == 5.0

    def test_large_value_capped_at_99_99(self) -> None:
        """10. '100' -> capped at 99.99."""
        assert parse_awc_visibility("100") == 99.99


# ===========================================================================
# map_cloud_cover
# ===========================================================================


class TestMapCloudCover:
    """Tests 11-15: map_cloud_cover."""

    def test_clr(self) -> None:
        """11. 'CLR' -> 'CLR'."""
        assert map_cloud_cover("CLR") == "CLR"

    def test_few(self) -> None:
        """12. 'FEW' -> 'FEW'."""
        assert map_cloud_cover("FEW") == "FEW"

    def test_cavok_maps_to_clr(self) -> None:
        """13. 'CAVOK' -> 'CLR'."""
        assert map_cloud_cover("CAVOK") == "CLR"

    def test_unknown_returns_none(self) -> None:
        """14. 'unknown' -> None."""
        assert map_cloud_cover("unknown") is None

    def test_none_returns_none(self) -> None:
        """15. None -> None."""
        assert map_cloud_cover(None) is None


# ===========================================================================
# station_to_icao / icao_to_station_code
# ===========================================================================


class TestStationIcaoConversion:
    """Tests 16-20: station <-> ICAO conversions."""

    def test_nyc_to_knyc(self) -> None:
        """16. 'NYC' -> 'KNYC'."""
        assert station_to_icao("NYC") == "KNYC"

    def test_knyc_to_nyc(self) -> None:
        """17. 'KNYC' -> 'NYC'."""
        assert icao_to_station_code("KNYC") == "NYC"

    def test_katl_to_atl(self) -> None:
        """18. 'KATL' -> 'ATL'."""
        assert icao_to_station_code("KATL") == "ATL"

    def test_two_letter_not_prepended(self) -> None:
        """19. 'AT' (2-letter) is not 3 chars, so stays 'AT' unchanged."""
        # station_to_icao only prepends K for exactly 3-letter codes
        assert station_to_icao("AT") == "AT"

    def test_cyyz_stays_unchanged(self) -> None:
        """20. 'CYYZ' (4-letter non-K prefix) stays 'CYYZ'."""
        assert icao_to_station_code("CYYZ") == "CYYZ"


# ===========================================================================
# celsius_to_f
# ===========================================================================


class TestCelsiusToF:
    """Tests 21-25: celsius_to_f."""

    def test_zero_celsius(self) -> None:
        """21. 0C -> 32.0F."""
        assert celsius_to_f(0.0) == 32.0

    def test_boiling_point(self) -> None:
        """22. 100C -> 212.0F."""
        assert celsius_to_f(100.0) == 212.0

    def test_negative_40_same_both_scales(self) -> None:
        """23. -40C -> -40.0F."""
        assert celsius_to_f(-40.0) == -40.0

    def test_go_matched_rounding_10_6(self) -> None:
        """24. 10.6C -> 51.1F (Go-matched rounding).

        10.6 * 9/5 + 32 = 51.08
        floor(51.08 * 10 + 0.5) / 10 = floor(511.3) / 10 = 51.1
        """
        result = celsius_to_f(10.6)
        assert result is not None
        assert result == 51.1

    def test_none_returns_none(self) -> None:
        """25. None -> None."""
        assert celsius_to_f(None) is None
