package system

import (
	"context"
	"kra/internal/biz/system"
	"testing"
	"time"
)

func errorString(value string) *string { return &value }

func newErrorRecordRepos(t *testing.T) (*auditRecorderRepo, *auditQueryRepo) {
	t.Helper()
	db, err := openWithDriver("sqlite", "file:"+t.Name()+"?mode=memory&cache=shared")
	if err != nil {
		t.Fatal(err)
	}
	if err = db.AutoMigrate(&errorRecordPO{}); err != nil {
		t.Fatal(err)
	}
	sqlDB, err := db.DB()
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { _ = sqlDB.Close() })
	data := &Data{gormDB: newReloadableDB(db, nil)}
	data.databaseReady.Store(true)
	return &auditRecorderRepo{data: data}, &auditQueryRepo{data: data}
}

func TestCreateErrorBeforeDatabaseInitializationIsNoop(t *testing.T) {
	db, err := openWithDriver("sqlite", "file:"+t.Name()+"?mode=memory&cache=shared")
	if err != nil {
		t.Fatal(err)
	}
	sqlDB, err := db.DB()
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { _ = sqlDB.Close() })
	recorder := &auditRecorderRepo{data: &Data{gormDB: newReloadableDB(db, nil)}}
	form := "后端"
	if err = recorder.CreateError(context.Background(), &system.ErrorRecord{Form: &form}); err != nil {
		t.Fatalf("uninitialized error write = %v, want nil", err)
	}
}

func TestCreateErrorPreservesNullableFieldsAndDefaultStatus(t *testing.T) {
	recorder, query := newErrorRecordRepos(t)
	createdAt := time.Date(2025, time.March, 4, 5, 6, 7, 0, time.UTC)
	form := "前端"
	if err := recorder.CreateError(context.Background(), &system.ErrorRecord{
		ID:        41,
		CreatedAt: createdAt,
		Form:      &form,
		Level:     "error",
	}); err != nil {
		t.Fatal(err)
	}

	got, err := query.FindError(context.Background(), 41)
	if err != nil {
		t.Fatal(err)
	}
	if got.Form == nil || *got.Form != form {
		t.Fatalf("form = %#v, want %q", got.Form, form)
	}
	if got.Info != nil || got.Solution != nil {
		t.Fatalf("nullable fields = (%#v, %#v), want nil", got.Info, got.Solution)
	}
	if got.Status != "未处理" {
		t.Fatalf("status = %q, want 未处理", got.Status)
	}
	if !got.CreatedAt.Equal(createdAt) {
		t.Fatalf("created_at = %v, want %v", got.CreatedAt, createdAt)
	}
}

func TestUpdateErrorDistinguishesOmittedAndExplicitEmptyFields(t *testing.T) {
	recorder, query := newErrorRecordRepos(t)
	form, info, solution := "后端", "错误内容", "解决方案"
	if err := recorder.CreateError(context.Background(), &system.ErrorRecord{
		Form:      &form,
		Info:      &info,
		Solution:  &solution,
		Level:     "error",
		RequestID: "request-old",
		TraceID:   "trace-old",
		Status:    "处理中",
	}); err != nil {
		t.Fatal(err)
	}

	items, _, err := query.ListErrors(context.Background(), 1, 10, nil)
	if err != nil || len(items) != 1 {
		t.Fatalf("list before update = (%d, %v)", len(items), err)
	}
	id := items[0].ID
	newForm := "服务端"
	if err = query.UpdateError(context.Background(), &system.ErrorRecord{ID: id, Form: &newForm}); err != nil {
		t.Fatal(err)
	}
	got, err := query.FindError(context.Background(), id)
	if err != nil {
		t.Fatal(err)
	}
	if got.Info == nil || *got.Info != info || got.Solution == nil || *got.Solution != solution {
		t.Fatalf("omitted fields changed: info=%#v solution=%#v", got.Info, got.Solution)
	}

	changedCreatedAt := time.Date(2024, time.January, 2, 3, 4, 5, 0, time.UTC)
	if err = query.UpdateError(context.Background(), &system.ErrorRecord{
		ID:        id,
		CreatedAt: changedCreatedAt,
		Form:      errorString(""),
		Info:      errorString(""),
		Solution:  errorString(""),
		RequestID: "request-new",
		TraceID:   "trace-new",
	}); err != nil {
		t.Fatal(err)
	}
	got, err = query.FindError(context.Background(), id)
	if err != nil {
		t.Fatal(err)
	}
	if got.Form == nil || *got.Form != "" || got.Info == nil || *got.Info != "" || got.Solution == nil || *got.Solution != "" {
		t.Fatalf("explicit empty fields were not persisted: form=%#v info=%#v solution=%#v", got.Form, got.Info, got.Solution)
	}
	if got.Level != "error" || got.Status != "处理中" {
		t.Fatalf("zero-value fields changed: level=%q status=%q", got.Level, got.Status)
	}
	if got.RequestID != "request-new" || got.TraceID != "trace-new" {
		t.Fatalf("trace fields = (%q, %q), want updated values", got.RequestID, got.TraceID)
	}
	if !got.CreatedAt.Equal(changedCreatedAt) {
		t.Fatalf("created_at = %v, want %v", got.CreatedAt, changedCreatedAt)
	}
}
