import type { DailyForecast, HourlyForecast, RawForecastSeries, RawWeatherForecast, WeatherForecast } from "@/types/forecast"; function asArray(value: unknown): unknown[] { return Array.isArray(value) ? value : []; } function readString(series: RawForecastSeries, key: keyof RawForecastSeries, index: number) { const value = asArray(series[key])[index]; return typeof value === "string" && value ? value : null; } function readNumber(series: RawForecastSeries, key: keyof RawForecastSeries, index: number) { const value = asArray(series[key])[index]; return typeof value === "number" && Number.isFinite(value) ? value : null; } function normalizeHourlyForecast(series: RawForecastSeries = {}): HourlyForecast[] { return asArray(series.time).flatMap((_, index) => { const time = readString(series, "time", index); if (!time) return []; return [{ time, temperature: readNumber(series, "temperature_2m", index), feelsLike: readNumber(series, "apparent_temperature", index), precipitationProbability: readNumber(series, "precipitation_probability", index), precipitation: readNumber(series, "precipitation", index), weatherCode: readNumber(series, "weather_code", index), windSpeed: readNumber(series, "wind_speed_10m", index), }]; }); } function normalizeDailyForecast(series: RawForecastSeries = {}): DailyForecast[] { return asArray(series.time).flatMap((_, index) => { const date = readString(series, "time", index); if (!date) return []; return [{ date, temperatureMax: readNumber(series, "temperature_2m_max", index), temperatureMin: readNumber(series, "temperature_2m_min", index), precipitationProbability: readNumber(series, "precipitation_probability_max", index), precipitation: readNumber(series, "precipitation_sum", index), weatherCode: readNumber(series, "weather_code", index), sunrise: readString(series, "sunrise", index), sunset: readString(series, "sunset", index), }]; }); } function normalizeForecast(raw: RawWeatherForecast): WeatherForecast { const latitude = Number(raw.latitude); const longitude = Number(raw.longitude); if (!Number.isFinite(latitude) || !Number.isFinite(longitude)) throw new Error("Forecast service returned invalid coordinates."); return { latitude, longitude, timezone: typeof raw.timezone === "string" ? raw.timezone : "Europe/Warsaw", hourly: normalizeHourlyForecast(raw.hourly), daily: normalizeDailyForecast(raw.daily), }; } export async function fetchForecast(latitude: number, longitude: number, signal?: AbortSignal) { const params = new URLSearchParams({ latitude: String(latitude), longitude: String(longitude) }); const response = await fetch(`/api/forecast?${params}`, { signal }); if (!response.ok) throw new Error("Unable to load forecast."); return normalizeForecast(await response.json() as RawWeatherForecast); }