from __future__ import annotations

import pytest

from src.weather_service import WeatherService, WeatherUpstreamError
from conftest import FakeClient, FakeResponse


@pytest.mark.asyncio
async def test_weather_normalization_and_wmo_translation() -> None:
    payload = {
        "hourly": {
            "time": ["2024-01-15T00:00", "2024-01-15T01:00"],
            "temperature_2m": [2.11, 1.84],
            "precipitation": [0.0, 0.12],
            "relative_humidity_2m": [85, 87],
            "wind_speed_10m": [12.51, 14.26],
            "weather_code": [3, 61],
        }
    }

    service = WeatherService(client=FakeClient(response=FakeResponse(payload)))
    result = await service.get_weather(48.86, 2.35, "2024-01-15", "2024-01-15")

    assert result["data"][0]["description"] == "Couvert"
    assert result["data"][1]["description"] == "Pluie légère"
    assert result["data"][0]["icon"] == "☁️"
    assert result["data"][1]["icon"] == "🌧️"
    assert result["data"][0]["temperature"] == 2.1
    assert result["data"][1]["precipitation"] == 0.1
    assert result["daily_summary"][0]["description"] == "Pluie légère"


@pytest.mark.asyncio
async def test_weather_wmo_null_fallback() -> None:
    payload = {
        "hourly": {
            "time": ["2024-01-15T00:00"],
            "temperature_2m": [2.1],
            "precipitation": [0.0],
            "relative_humidity_2m": [85],
            "wind_speed_10m": [12.5],
            "weather_code": [None],
        }
    }

    service = WeatherService(client=FakeClient(response=FakeResponse(payload)))
    result = await service.get_weather(48.86, 2.35, "2024-01-15", "2024-01-15")

    assert result["data"][0]["description"] == "Conditions non disponibles"
    assert result["data"][0]["icon"] == "❓"


@pytest.mark.asyncio
async def test_weather_upstream_error() -> None:
    service = WeatherService(client=FakeClient(fail=True))

    with pytest.raises(WeatherUpstreamError):
        await service.get_weather(48.86, 2.35, "2024-01-15", "2024-01-15")


@pytest.mark.asyncio
async def test_weather_handles_inconsistent_lengths() -> None:
    payload = {
        "hourly": {
            "time": ["2024-01-15T00:00", "2024-01-15T01:00"],
            "temperature_2m": [2.1],
            "precipitation": [0.0, 0.1],
            "relative_humidity_2m": [85, 87],
            "wind_speed_10m": [12.5, 14.2],
            "weather_code": [3, 61],
        }
    }

    service = WeatherService(client=FakeClient(response=FakeResponse(payload)))
    result = await service.get_weather(48.86, 2.35, "2024-01-15", "2024-01-15")

    assert len(result["data"]) == 1


@pytest.mark.asyncio
async def test_weather_handles_null_numeric_values() -> None:
    payload = {
        "hourly": {
            "time": ["1940-01-01T00:00"],
            "temperature_2m": [None],
            "precipitation": [None],
            "relative_humidity_2m": [None],
            "wind_speed_10m": [None],
            "weather_code": [3],
        }
    }

    service = WeatherService(client=FakeClient(response=FakeResponse(payload)))
    result = await service.get_weather(48.86, 2.35, "1940-01-01", "1940-01-01")

    row = result["data"][0]
    assert row["temperature"] is None
    assert row["precipitation"] is None
    assert row["humidity"] is None
    assert row["wind_speed"] is None


@pytest.mark.asyncio
async def test_daily_summary_multi_day_and_tie_break() -> None:
    payload = {
        "hourly": {
            "time": [
                "2024-01-15T00:00",
                "2024-01-15T01:00",
                "2024-01-15T02:00",
                "2024-01-16T00:00",
                "2024-01-16T01:00",
            ],
            "temperature_2m": [2.0, 4.0, None, None, None],
            "precipitation": [0.5, 0.0, None, None, None],
            "relative_humidity_2m": [80, 84, None, None, None],
            "wind_speed_10m": [10.0, 14.0, None, None, None],
            "weather_code": [3, 61, 61, 3, 61],
        }
    }

    service = WeatherService(client=FakeClient(response=FakeResponse(payload)))
    result = await service.get_weather(48.86, 2.35, "2024-01-15", "2024-01-16")

    first_day = result["daily_summary"][0]
    second_day = result["daily_summary"][1]

    assert first_day["date"] == "2024-01-15"
    assert first_day["temp_min"] == 2.0
    assert first_day["temp_max"] == 4.0
    assert first_day["precipitation_sum"] == 0.5
    assert first_day["humidity_avg"] == 82
    assert first_day["wind_speed_avg"] == 12.0
    assert first_day["description"] == "Pluie légère"
    assert first_day["icon"] == "🌧️"

    assert second_day["date"] == "2024-01-16"
    assert second_day["temp_min"] is None
    assert second_day["temp_max"] is None
    assert second_day["precipitation_sum"] is None
    assert second_day["humidity_avg"] is None
    assert second_day["wind_speed_avg"] is None
    assert second_day["description"] == "Pluie légère"
    assert second_day["icon"] == "🌧️"


@pytest.mark.asyncio
async def test_daily_summary_all_null_weather_codes() -> None:
    payload = {
        "hourly": {
            "time": ["2024-01-15T00:00", "2024-01-15T01:00"],
            "temperature_2m": [2.0, 3.0],
            "precipitation": [0.0, 0.2],
            "relative_humidity_2m": [80, 85],
            "wind_speed_10m": [10.0, 11.0],
            "weather_code": [None, None],
        }
    }

    service = WeatherService(client=FakeClient(response=FakeResponse(payload)))
    result = await service.get_weather(48.86, 2.35, "2024-01-15", "2024-01-15")

    summary = result["daily_summary"][0]
    assert summary["icon"] == "❓"
    assert summary["description"] == "Conditions non disponibles"
