package briefing import ( "fmt" "gitea.maximumdirect.net/eric/weatherreporter/internal/forecast" "gitea.maximumdirect.net/eric/weatherreporter/internal/module" "gitea.maximumdirect.net/eric/weatherreporter/internal/timeutil" ) type DerivedDailySummaryModule struct { Date string `json:"date,omitempty"` HighTempF *int `json:"high_temp_f,omitempty"` LowTempF *int `json:"low_temp_f,omitempty"` MaxPopPercent *int `json:"max_pop_percent,omitempty"` MaxPopWindow string `json:"max_pop_window,omitempty"` FirstPrecipHour string `json:"first_precip_hour,omitempty"` LastPrecipHour string `json:"last_precip_hour,omitempty"` ThunderMentioned bool `json:"thunder_mentioned"` MaxWindGustMph *int `json:"max_wind_gust_mph,omitempty"` HeatIndexMaxF *int `json:"heat_index_max_f,omitempty"` DominantConditions []string `json:"dominant_conditions,omitempty"` Hazards []string `json:"hazards,omitempty"` } func buildDerivedDailySummaryModule(ctx ModuleContext, _ any) (*module.Output, error) { summary := ctx.Derived.FirstDailySummary() if summary == nil { return nil, fmt.Errorf("daily summary facts are required") } value, err := derivedDailySummaryValue(*summary, ctx.Derived.PrecipTiming, ctx.Timezone) if err != nil { return nil, err } return &module.Output{ID: module.DerivedDailySummary, StanzaName: "derived_daily_summary", Value: value}, nil } func derivedDailySummaryValue(summary forecast.DailySummary, timing forecast.PrecipTiming, timezone string) (DerivedDailySummaryModule, error) { value := DerivedDailySummaryModule{ Date: summary.Date, ThunderMentioned: timing.ThunderMentioned, } conditions := map[string]struct{}{} hazards := map[string]struct{}{} var temperature forecast.Range var apparent forecast.Range var maxPop *forecast.TimedValue var maxGust *forecast.TimedValue var maxPopWindow timeutil.Period for _, daypart := range summary.Dayparts { addRange(&temperature, daypart.Temperature) addRange(&apparent, daypart.ApparentTemperature) if daypart.MaxPrecipitationProbability != nil { if maxPop == nil || daypart.MaxPrecipitationProbability.Value > maxPop.Value { copied := *daypart.MaxPrecipitationProbability maxPop = &copied maxPopWindow = daypart.Period } } maxTimedValue(&maxGust, daypart.PeakWindGust) if daypart.DominantCondition != "" { conditions[daypart.DominantCondition] = struct{}{} } for _, hazard := range hazardsForIndicators(daypart.Indicators) { hazards[hazard] = struct{}{} } } for _, alert := range summary.AlertOverlaps { if alert.Event != "" { hazards[alert.Event] = struct{}{} } } value.HighTempF = roundedInt(temperature.Max) value.LowTempF = roundedInt(temperature.Min) value.HeatIndexMaxF = roundedInt(apparent.Max) if maxPop != nil { value.MaxPopPercent = roundedInt(&maxPop.Value) value.MaxPopWindow = periodClockLabel(maxPopWindow, timezone) } if maxGust != nil { value.MaxWindGustMph = roundedInt(&maxGust.Value) } value.FirstPrecipHour = timedClockLabel(timing.FirstPrecipitation, timezone) value.LastPrecipHour = timedClockLabel(timing.LastPrecipitation, timezone) value.DominantConditions = sortedSet(conditions) value.Hazards = sortedSet(hazards) return value, nil }