package eino

import (
	"encoding/json"

	"github.com/cloudwego/eino/schema"
)

// board 的字段全是未导出的，而 Eino 的 checkpoint 序列化器只认导出字段——若直接让 compose
// 持久化 board，会落成空、resume 丢全部执行态。Eino 对「同时实现 json.Marshaler+Unmarshaler」
// 的类型改走自定义 JSON（见 internal/serialization checkMarshaler），故给 *board 实现一对 JSON
// 方法、映射到导出 DTO，即可把整个黑板按需持久化，而无需把 board 字段全导出（牵连几十处调用点）。
//
// 不持久化 fatalErr（error，transient——中断点处必为 nil）：审批中断时图尚未失败，
// 它是单次 Invoke 内的致命错标志，跨 resume 无意义。rejected 同理在中断点为 false，
// 但仍带上以求快照完整、零歧义。
type boardSnapshot struct {
	UID      string            `json:"uid,omitempty"`
	SID      string            `json:"sid,omitempty"`
	Query    string            `json:"query,omitempty"`
	Profile  string            `json:"profile,omitempty"`
	History  []*schema.Message `json:"history,omitempty"`
	KB       string            `json:"kb,omitempty"`
	Refs     []string          `json:"refs,omitempty"`
	ToolOut  []string          `json:"tool_out,omitempty"`
	Sections []reportSection   `json:"sections,omitempty"`
	Answer   string            `json:"answer,omitempty"`
	AgentOut []string          `json:"agent_out,omitempty"`
	Rejected bool              `json:"rejected,omitempty"`
}

// MarshalJSON 把黑板序列化为快照（Eino checkpoint 经此持久化整图执行态）。
func (b *board) MarshalJSON() ([]byte, error) {
	return json.Marshal(boardSnapshot{
		UID:      b.uid,
		SID:      b.sid,
		Query:    b.query,
		Profile:  b.profile,
		History:  b.history,
		KB:       b.kb,
		Refs:     b.refs,
		ToolOut:  b.toolOut,
		Sections: b.sections,
		Answer:   b.answer,
		AgentOut: b.agentOut,
		Rejected: b.rejected,
	})
}

// UnmarshalJSON 从快照还原黑板（resume 时 Eino 据此重建中断前的执行态）。
func (b *board) UnmarshalJSON(data []byte) error {
	var s boardSnapshot
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}
	b.uid = s.UID
	b.sid = s.SID
	b.query = s.Query
	b.profile = s.Profile
	b.history = s.History
	b.kb = s.KB
	b.refs = s.Refs
	b.toolOut = s.ToolOut
	b.sections = s.Sections
	b.answer = s.Answer
	b.agentOut = s.AgentOut
	b.rejected = s.Rejected
	return nil
}

// 注册 *board 的序列化类型名：Eino checkpoint 的 State 是 any，持久化时记类型名、
// resume 时据名还原具体类型再走 UnmarshalJSON。名字一经上线不可改（旧 checkpoint 据此解码）。
func init() {
	schema.RegisterName[*board]("sundynix_board")
}
