// Package briefing builds prompt-facing module values. package briefing import ( "time" "gitea.maximumdirect.net/eric/weatherreporter/internal/report" "gitea.maximumdirect.net/eric/weatherreporter/internal/timeutil" "gitea.maximumdirect.net/eric/weatherreporter/internal/weatherdata" ) // PreparedIdentity is the single prepared authority for report identity, // timing, configuration context, and source warnings. type PreparedIdentity struct { RunID string `json:"runId"` ReportID report.ID `json:"reportId"` Variant string `json:"variant,omitempty"` PromptID string `json:"promptId"` GeneratedAt time.Time `json:"generatedAt"` Units string `json:"units"` Timezone string `json:"timezone"` ValidPeriod timeutil.Period `json:"validPeriod"` Location *LocationContext `json:"location,omitempty"` SourceLocationID string `json:"sourceLocationId,omitempty"` SourceLocation string `json:"sourceLocation,omitempty"` SourceWarnings []weatherdata.SourceWarning `json:"sourceWarnings,omitempty"` } type LocationContext struct { ID string `json:"id,omitempty"` Name string `json:"name,omitempty"` Region string `json:"region,omitempty"` Timezone string `json:"timezone,omitempty"` } type BuildContext struct { Resolved report.Resolved Bundle *weatherdata.Bundle Units string Timezone string Location *LocationContext } func BuildPreparedIdentity(ctx BuildContext) PreparedIdentity { metadata := ctx.Resolved.Metadata() sourceLocationID, sourceLocation := sourceLocation(ctx.Bundle) return PreparedIdentity{ RunID: metadata.RunID, ReportID: metadata.ReportID, Variant: variantForReport(metadata.ReportID), PromptID: metadata.PromptID, GeneratedAt: metadata.GeneratedAt, Units: ctx.Units, Timezone: ctx.Timezone, ValidPeriod: metadata.ValidPeriod, Location: copyLocation(ctx.Location), SourceLocationID: sourceLocationID, SourceLocation: sourceLocation, SourceWarnings: append([]weatherdata.SourceWarning(nil), sourceWarnings(ctx.Bundle)...), } } func copyLocation(location *LocationContext) *LocationContext { if location == nil { return nil } copied := *location return &copied } func copyBool(value *bool) *bool { if value == nil { return nil } copied := *value return &copied } func copyInt(value *int) *int { if value == nil { return nil } copied := *value return &copied } func copyFloat(value *float64) *float64 { if value == nil { return nil } copied := *value return &copied } func copyTime(value *time.Time) *time.Time { if value == nil { return nil } copied := *value return &copied } func sourceLocation(bundle *weatherdata.Bundle) (string, string) { if bundle == nil { return "", "" } for _, run := range []*weatherdata.ForecastRun{bundle.Hourly, bundle.Narrative, bundle.Daily} { if run == nil { continue } if run.LocationID != "" || run.LocationName != "" { return run.LocationID, run.LocationName } } return "", "" } func sourceWarnings(bundle *weatherdata.Bundle) []weatherdata.SourceWarning { if bundle == nil { return nil } return bundle.Warnings } func variantForReport(id report.ID) string { switch id { case report.Daily, report.Today: return "today" case report.Tomorrow: return "tomorrow" default: return "" } }