package templates import ( "encoding/json" "fmt" "sort" "sync" ) // Registry holds all available templates (system + user overrides). type Registry struct { mu sync.RWMutex templates map[string]*Template } func NewRegistry() *Registry { return &Registry{templates: make(map[string]*Template)} } // LoadSystem reads system templates from embedded JSON. func (r *Registry) LoadSystem() error { data, err := systemTemplatesFS.ReadFile("system_templates.json") if err != nil { return err } var sysTemplates []Template if err := json.Unmarshal(data, &sysTemplates); err != nil { return err } r.mu.Lock() defer r.mu.Unlock() for _, t := range sysTemplates { cp := t r.templates[t.ID] = &cp } return nil } // Get returns a template by ID. func (r *Registry) Get(id string) (*Template, bool) { r.mu.RLock() defer r.mu.RUnlock() t, ok := r.templates[id] return t, ok } // Enabled returns all enabled templates sorted by type+id. func (r *Registry) Enabled() []*Template { r.mu.RLock() defer r.mu.RUnlock() var result []*Template for _, t := range r.templates { if t.Enabled { result = append(result, t) } } sort.Slice(result, func(i, j int) bool { if result[i].Type != result[j].Type { return result[i].Type < result[j].Type } return result[i].ID < result[j].ID }) return result } // All returns all registered templates sorted by type+id. func (r *Registry) All() []*Template { r.mu.RLock() defer r.mu.RUnlock() return sortedCopy(r.templates) } func sortedCopy(templates map[string]*Template) []*Template { result := make([]*Template, 0, len(templates)) for _, t := range templates { result = append(result, t) } sort.Slice(result, func(i, j int) bool { if result[i].Type != result[j].Type { return result[i].Type < result[j].Type } return result[i].ID < result[j].ID }) return result } // EnabledForParent returns templates that are allowed for a given parent type. func (r *Registry) EnabledForParent(parentType string) []*Template { r.mu.RLock() defer r.mu.RUnlock() var result []*Template for _, t := range r.templates { if !t.Enabled { continue } for _, allowed := range t.AllowedParentTypes { if allowed == "*" || allowed == parentType { result = append(result, t) break } } } sort.Slice(result, func(i, j int) bool { if result[i].Type != result[j].Type { return result[i].Type < result[j].Type } return result[i].ID < result[j].ID }) return result } // Enable enables a template by ID. func (r *Registry) Enable(id string) error { r.mu.Lock() defer r.mu.Unlock() t, ok := r.templates[id] if !ok { return fmt.Errorf("template %q not found", id) } t.Enabled = true return nil } // Disable disables a template by ID. func (r *Registry) Disable(id string) error { r.mu.Lock() defer r.mu.Unlock() t, ok := r.templates[id] if !ok { return fmt.Errorf("template %q not found", id) } t.Enabled = false return nil }