import { describeWmo } from './weather-codes.ts' export function buildHourlySeries(data: any, units: 'metric' | 'imperial') { const tempSuffix = units === 'metric' ? '°C' : '°F' const windSuffix = units === 'metric' ? 'km/h' : 'mph' const precipSuffix = units === 'metric' ? 'mm' : 'in' const rows = [] const hourly = data.hourly || {} const times = Array.isArray(hourly.time) ? hourly.time : [] for (let index = 0; index < times.length; index += 1) { rows.push({ time: hourly.time[index], condition: describeWmo(hourly.weathercode[index]), temperature: hourly.temperature_2m[index], temperatureDisplay: Math.round(hourly.temperature_2m[index]) + tempSuffix, feelsLike: hourly.apparent_temperature[index], feelsLikeDisplay: Math.round(hourly.apparent_temperature[index]) + tempSuffix, humidityPct: hourly.relativehumidity_2m[index], precipitationProbabilityPct: hourly.precipitation_probability[index], precipitation: hourly.precipitation[index], precipitationDisplay: String(hourly.precipitation[index]) + precipSuffix, windSpeed: hourly.windspeed_10m[index], windDirectionDeg: hourly.winddirection_10m[index], windDisplay: Math.round(hourly.windspeed_10m[index]) + windSuffix + ' @ ' + hourly.winddirection_10m[index] + '°', uvIndex: hourly.uv_index[index], }) } return rows } export function buildWeatherResponse(params: any) { const input = typeof params === 'object' && params ? params : {} const data = input.data const units = input.units === 'metric' ? 'metric' : 'imperial' const tempSuffix = units === 'metric' ? '°C' : '°F' const windSuffix = units === 'metric' ? 'km/h' : 'mph' const precipSuffix = units === 'metric' ? 'mm' : 'in' const daily = data.daily const current = data.current && typeof data.current === 'object' ? { time: data.current.time || null, weatherCode: data.current.weathercode, condition: describeWmo(data.current.weathercode), temperature: data.current.temperature_2m, temperatureDisplay: Math.round(data.current.temperature_2m) + tempSuffix, } : null const dailySummary = { date: input.date, location: input.displayName, type: input.isHistorical ? 'historical' : input.isForecast ? 'forecast' : 'today', weatherCode: daily.weathercode[0], condition: describeWmo(daily.weathercode[0]), high: daily.temperature_2m_max[0], low: daily.temperature_2m_min[0], feelsLikeHigh: daily.apparent_temperature_max[0], feelsLikeLow: daily.apparent_temperature_min[0], precipitationTotal: daily.precipitation_sum[0], precipitationProbabilityMaxPct: daily.precipitation_probability_max?.[0] ?? null, windMax: daily.windspeed_10m_max[0], uvIndexMax: daily.uv_index_max?.[0] ?? null, sunrise: daily.sunrise[0], sunset: daily.sunset[0], display: { high: Math.round(daily.temperature_2m_max[0]) + tempSuffix, low: Math.round(daily.temperature_2m_min[0]) + tempSuffix, feelsLikeHigh: Math.round(daily.apparent_temperature_max[0]) + tempSuffix, feelsLikeLow: Math.round(daily.apparent_temperature_min[0]) + tempSuffix, precipitationTotal: String(daily.precipitation_sum[0]) + precipSuffix, precipitationProbabilityMax: String(daily.precipitation_probability_max?.[0] ?? 'N/A') + '%', windMax: Math.round(daily.windspeed_10m_max[0]) + windSuffix, }, } const hourlySeries = buildHourlySeries(data, units) let hourly = null if (input.hour !== null && input.hour !== undefined) { const wanted = String(Number(input.hour)).padStart(2, '0') hourly = hourlySeries.find( (entry) => typeof entry.time === 'string' && entry.time.endsWith('T' + wanted + ':00'), ) || null } const previewLimit = Number.isFinite(Number(input.hourlyLimit)) ? Math.max(1, Number(input.hourlyLimit)) : 6 const hourlyPreview = hourlySeries.slice(0, previewLimit) const summaryLines = [ dailySummary.location + ' weather for ' + dailySummary.date + ' (' + dailySummary.type + ')', 'Condition: ' + dailySummary.condition, 'High/low: ' + dailySummary.display.high + ' / ' + dailySummary.display.low, 'Feels like: ' + dailySummary.display.feelsLikeHigh + ' / ' + dailySummary.display.feelsLikeLow, 'Precipitation: ' + dailySummary.display.precipitationTotal + ' total, max ' + dailySummary.display.precipitationProbabilityMax + ' chance', 'Wind max: ' + dailySummary.display.windMax, 'Sunrise/sunset: ' + dailySummary.sunrise + ' / ' + dailySummary.sunset, ] if (hourly) { summaryLines.push( 'Hour ' + String(Number(input.hour)).padStart(2, '0') + ':00: ' + hourly.condition + ', ' + hourly.temperatureDisplay + ', feels like ' + hourly.feelsLikeDisplay + ', precipitation ' + hourly.precipitationDisplay + ', wind ' + hourly.windDisplay, ) } return { location: { displayName: input.displayName, latitude: input.latitude, longitude: input.longitude, source: input.locationSource || 'unknown', }, date: input.date, units, source: input.source || 'open-meteo', stale: input.stale === true, attempts: input.attempts ?? null, recordedAt: input.recordedAt ?? null, fallbackError: input.fallbackError ?? null, daily: dailySummary, current, hourly, hourlyPreview, summary: summaryLines.join('\n'), } }