// Package prompts 是受管系统提示词的注册表：内置默认(随代码) + 运行期覆盖(文件/控制面)。
// 让各服务散落硬编码的 system prompt 集中、可不重编译地改/回滚/对比/灰度 —— prompt 版本化的地基。
package prompts

import (
	"encoding/json"
	"log"
	"os"
	"sort"
	"sync"
)

// 受管 prompt 的稳定键（key 即版本化/覆盖的寻址单位）。
const (
	GraphExtract    = "graph.extract"     // mcp-go：知识图谱三元组抽取
	EvalQuality     = "eval.quality"      // dispatcher：回答质量评审(harness)
	EvalRefine      = "eval.refine"       // dispatcher：低质回答自动修订
	GuardJailbreak  = "guard.jailbreak"   // dispatcher：输入越狱/注入分类
	CoordinatorLead = "coordinator.lead"  // dispatcher：多智能体协调者(lead)
	MemoryExtract   = "memory.extract"    // dispatcher：长期记忆对账
)

// Known 是平台受管的全部 prompt key（供管理端列出可配项；网关进程不登记默认，靠它枚举）。
var Known = []string{GraphExtract, EvalQuality, EvalRefine, GuardJailbreak, CoordinatorLead, MemoryExtract}

// Registry 持有默认与覆盖；Get 取覆盖优先、否则默认。并发安全。
type Registry struct {
	mu        sync.RWMutex
	defaults  map[string]string
	overrides map[string]string
}

func New() *Registry {
	return &Registry{defaults: map[string]string{}, overrides: map[string]string{}}
}

var global = New()

// SetDefault 登记某 key 的内置默认（基线版本，随代码走）。各服务启动时登记自己的 prompt。
func SetDefault(key, text string) { global.SetDefault(key, text) }
func (r *Registry) SetDefault(key, text string) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.defaults[key] = text
}

// SetOverride 运行期覆盖某 key（文件/控制面下发）。空串=清覆盖、回退默认。
func SetOverride(key, text string) { global.SetOverride(key, text) }
func (r *Registry) SetOverride(key, text string) {
	r.mu.Lock()
	defer r.mu.Unlock()
	if text == "" {
		delete(r.overrides, key)
		return
	}
	r.overrides[key] = text
}

// ApplyOverrides 用给定集合整体替换当前覆盖集（控制面热下发：DB 激活集为权威）。
// 空值条目忽略；传空 map 即清空所有覆盖、全回退内置默认。
func ApplyOverrides(m map[string]string) { global.ApplyOverrides(m) }
func (r *Registry) ApplyOverrides(m map[string]string) {
	r.mu.Lock()
	defer r.mu.Unlock()
	next := make(map[string]string, len(m))
	for k, v := range m {
		if v != "" {
			next[k] = v
		}
	}
	r.overrides = next
}

// Get 取生效内容：有覆盖用覆盖，否则用默认（都没有则空串）。
func Get(key string) string { return global.Get(key) }
func (r *Registry) Get(key string) string {
	r.mu.RLock()
	defer r.mu.RUnlock()
	if v, ok := r.overrides[key]; ok && v != "" {
		return v
	}
	return r.defaults[key]
}

// Keys 返回所有已登记默认的 key（排序，供管理面/启动日志）。
func Keys() []string { return global.Keys() }
func (r *Registry) Keys() []string {
	r.mu.RLock()
	defer r.mu.RUnlock()
	ks := make([]string, 0, len(r.defaults))
	for k := range r.defaults {
		ks = append(ks, k)
	}
	sort.Strings(ks)
	return ks
}

// LoadFile 从 JSON 文件({key:content})加载覆盖 —— env PROMPTS_FILE，启动时调一次。
// 不重编译即可改/回滚/对比 prompt；DB 控制面热切换是后续增量。
func LoadFile() {
	path := os.Getenv("PROMPTS_FILE")
	if path == "" {
		return
	}
	data, err := os.ReadFile(path)
	if err != nil {
		log.Printf("[prompts] 读 PROMPTS_FILE=%s 失败（用默认）: %v", path, err)
		return
	}
	var m map[string]string
	if err := json.Unmarshal(data, &m); err != nil {
		log.Printf("[prompts] 解析 PROMPTS_FILE 失败（用默认）: %v", err)
		return
	}
	n := 0
	for k, v := range m {
		SetOverride(k, v)
		n++
	}
	log.Printf("[prompts] 从 %s 加载 %d 条覆盖", path, n)
}
