from __future__ import annotations

from typing import Any

from app.cache import cache_get as redis_get, cache_set as redis_set
from app.config import (
    BRIGHTSKY_BASE_URL,
    CACHE_TTL_FORECAST,
    CACHE_TTL_OBSERVATIONS,
    OPEN_METEO_BASE_URL,
)
from app.database import get_cached_json, set_cached_json
from app.http_client import fetch_json

FORECAST_PARAMS = {
    "timezone": "Europe/Berlin",
    "current": "temperature_2m,relative_humidity_2m,apparent_temperature,precipitation,rain,showers,snowfall,weather_code,cloud_cover,pressure_msl,wind_speed_10m,wind_direction_10m,wind_gusts_10m",
    "hourly": "temperature_2m,relative_humidity_2m,precipitation_probability,precipitation,weather_code,cloud_cover,pressure_msl,wind_speed_10m,wind_direction_10m,wind_gusts_10m,visibility",
    "daily": "weather_code,temperature_2m_max,temperature_2m_min,precipitation_sum,precipitation_probability_max,wind_speed_10m_max,wind_gusts_10m_max,sunrise,sunset",
    "forecast_days": 7,
}


def _coord_key(lat: float, lon: float) -> tuple[float, float]:
    return round(lat, 4), round(lon, 4)


async def get_forecast(lat: float, lon: float) -> dict[str, Any]:
    lat_k, lon_k = _coord_key(lat, lon)
    redis_key = f"forecast:{lat_k}:{lon_k}"

    cached = await redis_get(redis_key)
    if cached:
        return {"source": OPEN_METEO_BASE_URL, "lat": lat, "lon": lon, "data": cached, "cached": True}

    cached = await get_cached_json("forecast_cache", {"lat": lat_k, "lon": lon_k}, CACHE_TTL_FORECAST)
    if cached:
        await redis_set(redis_key, cached, CACHE_TTL_FORECAST)
        return {"source": OPEN_METEO_BASE_URL, "lat": lat, "lon": lon, "data": cached, "cached": True}

    data = await fetch_json(
        f"{OPEN_METEO_BASE_URL}/forecast",
        params={"latitude": lat, "longitude": lon, **FORECAST_PARAMS},
    )
    await set_cached_json("forecast_cache", {"lat": lat_k, "lon": lon_k}, data)
    await redis_set(redis_key, data, CACHE_TTL_FORECAST)
    return {"source": OPEN_METEO_BASE_URL, "lat": lat, "lon": lon, "data": data, "cached": False}


async def get_observations(lat: float, lon: float) -> dict[str, Any]:
    lat_k, lon_k = _coord_key(lat, lon)
    redis_key = f"observations:{lat_k}:{lon_k}"

    cached = await redis_get(redis_key)
    if cached:
        return {"source": BRIGHTSKY_BASE_URL, "lat": lat, "lon": lon, "data": cached, "cached": True}

    cached = await get_cached_json("observations_cache", {"lat": lat_k, "lon": lon_k}, CACHE_TTL_OBSERVATIONS)
    if cached:
        await redis_set(redis_key, cached, CACHE_TTL_OBSERVATIONS)
        return {"source": BRIGHTSKY_BASE_URL, "lat": lat, "lon": lon, "data": cached, "cached": True}

    data = await fetch_json(f"{BRIGHTSKY_BASE_URL}/current_weather", params={"lat": lat, "lon": lon})
    await set_cached_json("observations_cache", {"lat": lat_k, "lon": lon_k}, data)
    await redis_set(redis_key, data, CACHE_TTL_OBSERVATIONS)
    return {"source": BRIGHTSKY_BASE_URL, "lat": lat, "lon": lon, "data": data, "cached": False}
