import { toNumber } from "@/lib/weather-utils"; import type { ImgwCurrentWeather, RawImgwHybridWeatherResponse, RawImgwHybridWeatherRow } from "@/types/imgw-current"; function toCelsius(value: unknown) { const temperature = toNumber(value); if (temperature === null) return null; return temperature > 150 ? temperature - 273.15 : temperature; } function toHectopascals(value: unknown) { const pressure = toNumber(value); if (pressure === null) return null; return pressure > 2_000 ? pressure / 100 : pressure; } function normalizeDate(value: unknown) { if (typeof value !== "string") return null; const date = new Date(value); return Number.isNaN(date.getTime()) ? null : date.toISOString(); } function getWeatherCode(iconCode: unknown) { if (typeof iconCode !== "string") return null; const match = iconCode.match(/z(\d{2})/i); return match ? Number(match[1]) : null; } function getCondition(weatherCode: number | null, rainfall10m: number | null, snowfall10m: number | null) { if (weatherCode !== null && weatherCode >= 95) return "thunderstorm" as const; if ((snowfall10m ?? 0) > 0) return "snow" as const; if ((rainfall10m ?? 0) > 0) return "rain" as const; return null; } export function normalizeImgwCurrentWeather(payload: RawImgwHybridWeatherResponse): ImgwCurrentWeather | null { if (!payload.data?.Valid || !Array.isArray(payload.data.Data)) return null; const rows = payload.data.Data .filter((candidate): candidate is RawImgwHybridWeatherRow => { if (!candidate || typeof candidate !== "object") return false; return candidate.Type === "Type_Ten_Minutes" && normalizeDate(candidate.Date) !== null; }) .sort((left, right) => String(left.Date).localeCompare(String(right.Date))); const fullRow = rows.find((candidate) => typeof candidate.MODEL === "string" && candidate.MODEL.includes("AROME")); const precipitationRow = rows.find((candidate) => candidate.Precipitation10m !== undefined); const row = fullRow ?? precipitationRow; if (!row) return null; const measuredAt = normalizeDate(row.Date); if (!measuredAt) return null; const rainfall10m = toNumber(row.Rain10m); const snowfall10m = toNumber(row.Snow10m); const weatherCode = getWeatherCode(row.Icon10); return { coverage: fullRow ? "full" : "precipitation-only", measuredAt, temperature: toCelsius(row.Temperature), feelsLike: toCelsius(row.Chill), windSpeed: toNumber(row.Wind_Speed), windDirection: toNumber(row.Wind_Dir), humidity: toNumber(row.Humidity), pressure: toHectopascals(row.PressureMSL), precipitation10m: toNumber(row.Precipitation10m), rainfall10m, snowfall10m, cloudCover: toNumber(row.Cloud), weatherCode, condition: getCondition(weatherCode, rainfall10m, snowfall10m), }; } export async function fetchImgwCurrentWeather(latitude: number, longitude: number, signal?: AbortSignal) { const params = new URLSearchParams({ latitude: String(latitude), longitude: String(longitude) }); const response = await fetch(`/api/imgw-current?${params}`, { signal }); if (!response.ok) throw new Error("Nie udało się pobrać bieżącej analizy IMGW Hybrid."); return normalizeImgwCurrentWeather(await response.json() as RawImgwHybridWeatherResponse); }