2026-06-15 12:24:47 +00:00
package generatedtext
import (
"fmt"
"gitea.maximumdirect.net/eric/weatherreporter/internal/briefing"
"gitea.maximumdirect.net/eric/weatherreporter/internal/facts"
"gitea.maximumdirect.net/eric/weatherreporter/internal/module"
"gitea.maximumdirect.net/eric/weatherreporter/internal/report"
"gitea.maximumdirect.net/eric/weatherreporter/internal/reporttemplate"
)
const (
schemaIDHourly = "hourly"
2026-06-15 16:23:13 +00:00
schemaIDDaily = "daily"
2026-06-15 14:45:49 +00:00
schemaIDToday = "today"
2026-06-15 12:24:47 +00:00
schemaIDTomorrow = "tomorrow"
templateIDHourly = "hourly"
2026-06-15 16:23:13 +00:00
templateIDDaily = "daily"
2026-06-15 14:45:49 +00:00
templateIDToday = "today"
2026-06-15 12:24:47 +00:00
templateIDTomorrow = "tomorrow"
)
type validator func ( [ ] byte ) ( any , [ ] byte , error )
type renderContextBuilder func ( report . ID , string , briefing . Metadata , module . Snapshot , facts . CollectedFacts , facts . DerivedFacts , any ) ( any , error )
type catalogEntry struct {
2026-06-15 12:52:18 +00:00
schemaID string
templateID string
validate validator
renderContextBuilder renderContextBuilder
2026-06-15 12:24:47 +00:00
}
type Handler struct {
2026-06-15 12:52:18 +00:00
reportID report . ID
schemaID string
templateID string
validate validator
renderContextBuilder renderContextBuilder
2026-06-15 12:24:47 +00:00
}
var catalog = [ ] catalogEntry {
{
2026-06-15 12:52:18 +00:00
schemaID : schemaIDHourly ,
templateID : templateIDHourly ,
validate : validateHourly ,
renderContextBuilder : buildHourlyContext ,
2026-06-15 12:24:47 +00:00
} ,
2026-06-15 16:23:13 +00:00
{
2026-06-15 16:29:18 +00:00
schemaID : schemaIDDaily ,
templateID : templateIDDaily ,
validate : validateDaily ,
renderContextBuilder : buildDailyContext ,
2026-06-15 16:23:13 +00:00
} ,
2026-06-15 14:45:49 +00:00
{
schemaID : schemaIDToday ,
templateID : templateIDToday ,
validate : validateToday ,
renderContextBuilder : buildTodayContext ,
} ,
2026-06-15 12:24:47 +00:00
{
2026-06-15 12:52:18 +00:00
schemaID : schemaIDTomorrow ,
templateID : templateIDTomorrow ,
validate : validateTomorrow ,
renderContextBuilder : buildTomorrowContext ,
2026-06-15 12:24:47 +00:00
} ,
}
func LookupDefinition ( definition report . Definition ) ( Handler , error ) {
if definition . GenerationMode != report . GenerationModeGeneratedTextTemplate {
return Handler { } , fmt . Errorf ( "report %q uses generation mode %q, not %q" , definition . ID , definition . GenerationMode , report . GenerationModeGeneratedTextTemplate )
}
var schemaKnown , templateKnown bool
for _ , entry := range catalog {
if entry . schemaID == definition . GeneratedTextSchemaID {
schemaKnown = true
}
if entry . templateID == definition . TemplateID {
templateKnown = true
}
if entry . schemaID == definition . GeneratedTextSchemaID && entry . templateID == definition . TemplateID {
return Handler {
2026-06-15 12:52:18 +00:00
reportID : definition . ID ,
schemaID : entry . schemaID ,
templateID : entry . templateID ,
validate : entry . validate ,
renderContextBuilder : entry . renderContextBuilder ,
2026-06-15 12:24:47 +00:00
} , nil
}
}
if ! schemaKnown {
return Handler { } , fmt . Errorf ( "generated text schema %q is not supported for report %q" , definition . GeneratedTextSchemaID , definition . ID )
}
if ! templateKnown {
return Handler { } , fmt . Errorf ( "report template %q is not supported for report %q" , definition . TemplateID , definition . ID )
}
return Handler { } , fmt . Errorf ( "generated text schema %q and report template %q are not supported together for report %q" , definition . GeneratedTextSchemaID , definition . TemplateID , definition . ID )
}
func ( h Handler ) SchemaID ( ) string {
return h . schemaID
}
func ( h Handler ) TemplateID ( ) string {
return h . templateID
}
func ( h Handler ) Schema ( ) ( [ ] byte , error ) {
data , err := reporttemplate . Schema ( h . schemaID )
if err != nil {
return nil , fmt . Errorf ( "load generated text schema %q for report %q: %w" , h . schemaID , h . reportID , err )
}
return data , nil
}
func ( h Handler ) Template ( ) ( string , error ) {
source , err := reporttemplate . Template ( h . templateID )
if err != nil {
return "" , fmt . Errorf ( "load report template %q for report %q: %w" , h . templateID , h . reportID , err )
}
return source , nil
}
func ( h Handler ) Validate ( data [ ] byte ) ( any , [ ] byte , error ) {
if h . validate == nil {
return nil , nil , fmt . Errorf ( "generated text validator is not registered for schema %q on report %q" , h . schemaID , h . reportID )
}
return h . validate ( data )
}
func ( h Handler ) BuildRenderContext ( metadata briefing . Metadata , snapshot module . Snapshot , collected facts . CollectedFacts , derived facts . DerivedFacts , generated any ) ( any , error ) {
2026-06-15 12:52:18 +00:00
if h . renderContextBuilder == nil {
2026-06-15 12:24:47 +00:00
return nil , fmt . Errorf ( "render-context builder is not registered for template %q on report %q" , h . templateID , h . reportID )
}
2026-06-15 12:52:18 +00:00
return h . renderContextBuilder ( h . reportID , h . templateID , metadata , snapshot , collected , derived , generated )
2026-06-15 12:24:47 +00:00
}
func ( h Handler ) Render ( data any ) ( [ ] byte , error ) {
rendered , err := reporttemplate . Render ( h . templateID , data )
if err != nil {
return nil , fmt . Errorf ( "render report template %q for report %q: %w" , h . templateID , h . reportID , err )
}
return rendered , nil
}
func validateHourly ( data [ ] byte ) ( any , [ ] byte , error ) {
return ValidateHourly ( data )
}
2026-06-15 16:23:13 +00:00
func validateDaily ( data [ ] byte ) ( any , [ ] byte , error ) {
return ValidateDaily ( data )
}
2026-06-15 14:45:49 +00:00
func validateToday ( data [ ] byte ) ( any , [ ] byte , error ) {
return ValidateToday ( data )
}
2026-06-15 12:24:47 +00:00
func validateTomorrow ( data [ ] byte ) ( any , [ ] byte , error ) {
return ValidateTomorrow ( data )
}
func buildHourlyContext ( reportID report . ID , templateID string , metadata briefing . Metadata , snapshot module . Snapshot , collected facts . CollectedFacts , derived facts . DerivedFacts , generated any ) ( any , error ) {
hourly , ok := generated . ( Hourly )
if ! ok {
return nil , fmt . Errorf ( "report template %q requires hourly generated text for report %q" , templateID , reportID )
}
return BuildHourlyRenderContext ( metadata , snapshot , hourly , collected , derived )
}
2026-06-15 16:29:18 +00:00
func buildDailyContext ( reportID report . ID , templateID string , metadata briefing . Metadata , snapshot module . Snapshot , collected facts . CollectedFacts , derived facts . DerivedFacts , generated any ) ( any , error ) {
daily , ok := generated . ( Daily )
if ! ok {
return nil , fmt . Errorf ( "report template %q requires daily generated text for report %q" , templateID , reportID )
}
return BuildDailyRenderContext ( metadata , snapshot , daily , collected , derived )
}
2026-06-15 14:45:49 +00:00
func buildTodayContext ( reportID report . ID , templateID string , metadata briefing . Metadata , snapshot module . Snapshot , collected facts . CollectedFacts , derived facts . DerivedFacts , generated any ) ( any , error ) {
today , ok := generated . ( Today )
if ! ok {
return nil , fmt . Errorf ( "report template %q requires today generated text for report %q" , templateID , reportID )
}
return BuildTodayRenderContext ( metadata , snapshot , today , collected , derived )
}
2026-06-15 12:24:47 +00:00
func buildTomorrowContext ( reportID report . ID , templateID string , metadata briefing . Metadata , snapshot module . Snapshot , collected facts . CollectedFacts , derived facts . DerivedFacts , generated any ) ( any , error ) {
tomorrow , ok := generated . ( Tomorrow )
if ! ok {
return nil , fmt . Errorf ( "report template %q requires tomorrow generated text for report %q" , templateID , reportID )
}
return BuildTomorrowRenderContext ( metadata , snapshot , tomorrow , collected , derived )
}