package runtimeassembly

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

	database "github.com/nexuscrm/db"
	"github.com/nexuscrm/permissions"
	"github.com/nexuscrm/persistence"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
)

func TestCurrentPageLayoutAutoNumberAuthorityOnTiDB(t *testing.T) {
	ctx, cancel := context.WithTimeout(t.Context(), 45*time.Second)
	defer cancel()
	db, writer := newLayoutRuntimeTestDB(t, ctx, constants.TableUserRole, constants.TableObject, constants.TableField, constants.TablePageLayout, constants.TableLayoutAssignment)
	exec := func(statement string, args ...any) {
		t.Helper()
		if _, err := writer.ExecContext(ctx, statement, args...); err != nil {
			t.Fatal(err)
		}
	}
	exec(`INSERT INTO _System_Object (Id,ApiName,TableType,Label,SharingModel) VALUES ('object-a','WorkItem','standard_object','Work item','Private')`)
	exec(`INSERT INTO _System_Field (Id,ObjectId,ApiName,Label,Type,auto_number_format) VALUES ('legacy','object-a','LegacyNumber','Legacy','autonumber',NULL),('format','object-a','FormatNumber','Format','text','N-{000}'),('ordinary','object-a','Subject','Subject','text',NULL)`)
	raw := `{"id":"layout-a","objectApiName":"WorkItem","layoutName":"Main","type":"Detail","sections":[{"id":"main","fields":["LegacyNumber","FORMATNUMBER","Subject"]}]}`
	// Marshal the actual model so the fixture follows its public storage shape.
	var layout models.PageLayout
	if err := json.Unmarshal([]byte(raw), &layout); err != nil {
		t.Fatal(err)
	}
	if len(layout.Sections) != 1 || len(layout.Sections[0].Fields) != 3 {
		t.Fatalf("invalid fixture: %#v", layout)
	}
	encoded, err := json.Marshal(layout)
	if err != nil {
		t.Fatal(err)
	}
	exec(`INSERT INTO _System_PageLayout (Id,ObjectApiName,LayoutName,Config,Source,IsCustomized) VALUES ('layout-a','WorkItem','Main',?,'admin_created',1)`, encoded)
	exec(`INSERT INTO _System_LayoutAssignment (Id,ObjectApiName,LayoutId,Specificity,RouteSource) VALUES ('assignment-a','WorkItem','layout-a',0,'admin_authored')`)
	runtime, err := NewPageLayoutRuntime(database.NewConnectionFromDB(db), permissions.NewPermissionService(persistence.NewPermissionRepository(db), nil, nil))
	if err != nil {
		t.Fatal(err)
	}
	check := func(want []string) {
		t.Helper()
		layouts, err := runtime.Engine.ResolveCurrentPageLayouts(ctx, "WorkItem", "", nil, []string{"", "rt-other"})
		if err != nil {
			t.Fatal(err)
		}
		for _, key := range []string{"", "rt-other"} {
			if got := layouts[key].Sections[0].Fields; !reflect.DeepEqual(got, want) {
				t.Fatalf("fields[%q]=%v want=%v", key, got, want)
			}
		}
	}
	check([]string{"Subject"})
	exec(`UPDATE _System_Field SET auto_number_format=NULL WHERE Id='format'`)
	check([]string{"FORMATNUMBER", "Subject"})
	exec(`UPDATE _System_Field SET auto_number_format='S-{000}' WHERE Id='ordinary'`)
	check([]string{"FORMATNUMBER"})
	var stored string
	if err := db.QueryRowContext(ctx, `SELECT Config FROM _System_PageLayout WHERE Id='layout-a'`).Scan(&stored); err != nil {
		t.Fatal(err)
	}
	var unchanged models.PageLayout
	if err := json.Unmarshal([]byte(stored), &unchanged); err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(unchanged.Sections, layout.Sections) {
		t.Fatal("rendering modified authored sections")
	}
	exec(`DROP TABLE _System_Field`)
	if _, err := runtime.Engine.ResolveCurrentPageLayouts(ctx, "WorkItem", "", nil, []string{""}); err == nil {
		t.Fatal("missing field authority accepted")
	}
}
