package combatturns import ( "bytes" "encoding/json" "fmt" ) type extractionResponse struct { CombatTurns []combatTurnResponse `json:"combat_turns"` } type combatTurnResponse struct { Actor string `json:"actor"` TurnKind string `json:"turn_kind"` Round *int `json:"round"` Actions []combatActionResponse `json:"actions"` Summary string `json:"summary"` SourceRefs []combatSourceRefResponse `json:"source_refs"` } type combatActionResponse struct { Category string `json:"category"` Declaration string `json:"declaration"` Targets []string `json:"targets"` Resolution *string `json:"resolution"` } type combatSourceRefResponse struct { StartUnitID int `json:"start_unit_id"` EndUnitID int `json:"end_unit_id"` } func (response *combatTurnResponse) UnmarshalJSON(content []byte) error { type responseWire struct { Actor string `json:"actor"` TurnKind string `json:"turn_kind"` Round json.RawMessage `json:"round"` Actions []combatActionResponse `json:"actions"` Summary string `json:"summary"` SourceRefs []combatSourceRefResponse `json:"source_refs"` } var wire responseWire if err := json.Unmarshal(content, &wire); err != nil { return err } round, err := decodeRequiredNullableInt(wire.Round, "round") if err != nil { return err } *response = combatTurnResponse{ Actor: wire.Actor, TurnKind: wire.TurnKind, Round: round, Actions: wire.Actions, Summary: wire.Summary, SourceRefs: wire.SourceRefs, } return nil } func (response *combatActionResponse) UnmarshalJSON(content []byte) error { type responseWire struct { Category string `json:"category"` Declaration string `json:"declaration"` Targets []string `json:"targets"` Resolution json.RawMessage `json:"resolution"` } var wire responseWire if err := json.Unmarshal(content, &wire); err != nil { return err } resolution, err := decodeRequiredNullableString(wire.Resolution, "resolution") if err != nil { return err } *response = combatActionResponse{ Category: wire.Category, Declaration: wire.Declaration, Targets: wire.Targets, Resolution: resolution, } return nil } func decodeRequiredNullableInt(raw json.RawMessage, field string) (*int, error) { if len(raw) == 0 { return nil, fmt.Errorf("%s must be present", field) } if bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return nil, nil } var value int if err := json.Unmarshal(raw, &value); err != nil { return nil, fmt.Errorf("%s must be an integer or null: %w", field, err) } return &value, nil } func decodeRequiredNullableString(raw json.RawMessage, field string) (*string, error) { if len(raw) == 0 { return nil, fmt.Errorf("%s must be present", field) } if bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return nil, nil } var value string if err := json.Unmarshal(raw, &value); err != nil { return nil, fmt.Errorf("%s must be a string or null: %w", field, err) } return &value, nil }