package eino

import (
	"encoding/json"
	"reflect"
	"testing"

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

// board 必须同时实现 json.Marshaler+Unmarshaler，Eino checkpoint 才会走自定义 JSON 路径
// 持久化未导出字段；任一缺失都会让序列化器回退到「只存导出字段」=空 board。
var (
	_ json.Marshaler   = (*board)(nil)
	_ json.Unmarshaler = (*board)(nil)
)

// TestBoardSnapshotRoundtrip 钉死黑板快照往返：中断点的全部执行态都能无损还原（resume 不丢状态）。
func TestBoardSnapshotRoundtrip(t *testing.T) {
	orig := &board{
		uid:     "u42",
		sid:     "s7",
		query:   "介绍杭州西湖",
		profile: "用户偏好简洁",
		history: []*schema.Message{schema.UserMessage("上一轮"), schema.AssistantMessage("上一轮回答", nil)},
		kb:      "u42/travel",
		refs:    []string{"西湖十景…", "苏堤春晓…"},
		toolOut: []string{"[wiki] 杭州…"},
		sections: []reportSection{
			{Heading: "概况", Body: "西湖位于杭州。"},
		},
		answer:   "西湖是…",
		agentOut: []string{"草稿一", "草稿二"},
		// fatalErr 故意置非空：快照应丢弃它（transient），不应影响往返。
		fatalErr: errRejected,
	}

	data, err := json.Marshal(orig)
	if err != nil {
		t.Fatalf("marshal: %v", err)
	}

	var got board
	if err := json.Unmarshal(data, &got); err != nil {
		t.Fatalf("unmarshal: %v", err)
	}

	// 持久化字段逐一比对。
	if got.uid != orig.uid || got.sid != orig.sid || got.query != orig.query ||
		got.profile != orig.profile || got.kb != orig.kb || got.answer != orig.answer {
		t.Fatalf("标量字段未还原: %+v", got)
	}
	if !reflect.DeepEqual(got.refs, orig.refs) || !reflect.DeepEqual(got.toolOut, orig.toolOut) ||
		!reflect.DeepEqual(got.agentOut, orig.agentOut) || !reflect.DeepEqual(got.sections, orig.sections) {
		t.Fatalf("切片字段未还原: %+v", got)
	}
	if len(got.history) != len(orig.history) || got.history[0].Content != "上一轮" {
		t.Fatalf("history 未还原: %+v", got.history)
	}
	// fatalErr 是 transient，快照不持久化 → 还原后必为 nil。
	if got.fatalErr != nil {
		t.Fatalf("fatalErr 不应被持久化，got %v", got.fatalErr)
	}
}
