package catalogsnapshot

import (
	"bytes"
	"reflect"
	"testing"

	"github.com/nexuscrm/kernel/pkg/schemautil"
	"github.com/nexuscrm/shared/pkg/models"
	layoutauthoringv1 "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/layoutauthoringv1"
)

func TestCreateInputRequirementsUseMutationDerivedDefaults(t *testing.T) {
	input := layoutAuthoringCompileInput()
	for _, object := range input.Objects {
		if object.Metadata.APIName == "WorkItem" {
			models.FindField(object.Metadata, "Subject").Required = true
		}
	}
	input.Projections = append(input.Projections, RuntimeProjectionInput{
		CatalogRevision: testRevision, AppInstallationID: testInstallA,
		CapabilityID: testMutationCapability, Profile: ProjectionRecordMutationV1,
		ObjectAPINames: []string{"WorkItem", "Workspace", "Unrelated"},
	})
	input.MutationDefinitions = []MutationDefinitionInput{{CatalogRevision: testRevision, AutoNumberRule: &AutoNumberRule{
		FieldID: "field-subject", ObjectAPIName: "WorkItem", FieldAPIName: "Subject",
		Format: "WI-{0000}", Start: 1, Scope: "global", DateSource: "assigned_at", OnChange: "keep_existing",
	}}}
	var previousStored *layoutauthoringv1.StoredLayout
	for _, hasRule := range []bool{true, false} {
		if !hasRule {
			input.MutationDefinitions = nil
			input = withRevision(input, testRevision+1)
			for i := range input.LayoutAuthoringAggregates {
				input.LayoutAuthoringAggregates[i].CatalogRevision = input.Lineage.CatalogRevision
			}
		}
		effective, err := BuildEffectiveMetadata(input)
		if err != nil {
			t.Fatal(err)
		}
		before := effective.Bytes()
		required, err := effective.CreateRequiredInputFields()
		if err != nil {
			t.Fatal(err)
		}
		want := []string{}
		if !hasRule {
			want = []string{"Subject"}
		}
		if !reflect.DeepEqual(required["WorkItem"], want) {
			t.Fatalf("rule=%t required=%#v want=%#v", hasRule, required, want)
		}
		artifact, err := CompileEffectiveMetadata(effective)
		if err != nil {
			t.Fatal(err)
		}
		snapshot := mustOpenSnapshot(t, artifact)
		for _, key := range []ProjectionKey{
			{AppInstallationID: testInstallA, CapabilityID: testMutationCapability},
			{AppInstallationID: testInstallA, CapabilityID: layoutauthoringv1.CapabilityName},
		} {
			artifact, err := ProjectRuntimeMetadataView(snapshot, key)
			if err != nil {
				t.Fatal(err)
			}
			view := mustOpenView(t, artifact)
			if key.CapabilityID == testMutationCapability {
				object, _ := view.Object("WorkItem")
				if !reflect.DeepEqual(schemautil.RequiredCreateInputFields(object), want) {
					t.Fatal("create requirements differ from actual mutation schema")
				}
				if models.FindField(object, "Subject").DefaultedOnCreate != hasRule {
					t.Fatal("rule/default derivation differs")
				}
			} else {
				stored, ok := view.LayoutAuthoringStoredLayout("layout-work-item")
				if !ok || stored.CreateContext == nil || !reflect.DeepEqual(stored.CreateContext.RequiredFields, want) {
					t.Fatalf("layout context=%#v", stored.CreateContext)
				}
				if previousStored != nil && (stored.ResourceVersion != previousStored.ResourceVersion || stored.AggregateVersion != previousStored.AggregateVersion || stored.WorkspaceVersion != previousStored.WorkspaceVersion) {
					t.Fatal("rule change modified layout write preconditions")
				}
				previousStored = &stored
			}
		}
		if !bytes.Equal(before, effective.Bytes()) {
			t.Fatal("derivation changed immutable source bytes")
		}
		if models.FindField(input.Objects[0].Metadata, "Subject").DefaultedOnCreate {
			t.Fatal("derived flag leaked into raw input")
		}
		required["WorkItem"] = []string{"CallerChanged"}
		again, err := effective.CreateRequiredInputFields()
		if err != nil || !reflect.DeepEqual(again["WorkItem"], want) {
			t.Fatalf("returned context changed source: %v", err)
		}
	}
	if _, err := (EffectiveMetadata{}).CreateRequiredInputFields(); err == nil {
		t.Fatal("unavailable source became known-empty requirements")
	}
}
