//go:build integration

package catalogreconcile

import (
	"context"
	"strings"
	"testing"

	nexusdb "github.com/nexuscrm/db"
	"github.com/nexuscrm/metadata/catalogsnapshot"
	"github.com/nexuscrm/persistence"
	"github.com/nexuscrm/shared/pkg/models"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/layoutauthoringv1"
)

func TestStoredLayoutPublicationHistoricalObjectAliasesTiDB(t *testing.T) {
	// Reuse the real TiDB fixture and canonical L0 schema bootstrap. Do not
	// substitute a reader stub: this test must exercise the released Core pin.
	db := openConnectorExecutionTiDB(t)
	for _, statement := range []string{
		`INSERT INTO _System_Object (Id, ApiName, Label, PluralLabel, ListFields, IsDeleted)
		 VALUES ('object-system-file', '_System_File', 'File', 'Files', '["Id"]', 0)`,
		`INSERT INTO _System_PageLayout
		 (Id, ObjectApiName, LayoutName, Type, Config, Source, IsCustomized, IsDefault, IsDeleted, LayoutVersion, GenerationVersion)
		 VALUES ('default__system_file', '_system_file', 'Default', 'Detail', '{}', 'admin_created', 1, 0, 0, 1, 0)`,
		`INSERT INTO _System_LayoutAssignment (Id, ObjectApiName, LayoutId, Specificity, RouteSource)
		 VALUES ('assignment-file-default', '_system_file', 'default__system_file', 0, 'admin_authored')`,
	} {
		if _, err := db.ExecContext(t.Context(), statement); err != nil {
			t.Fatal(err)
		}
	}
	repository := persistence.NewMetadataRepository(db)
	reader, err := NewRepositoryMetadataReader(repository)
	if err != nil {
		t.Fatal(err)
	}
	manager := persistence.NewTransactionManager(nexusdb.NewConnectionFromDB(db))
	object := validObject("_System_File")
	object.ListFields = []string{"Id"}
	readPublication := func() (catalogsnapshot.Artifact, error) {
		input := catalogsnapshot.CompileInput{
			OrgID:   "org-test",
			Lineage: catalogsnapshot.Lineage{CatalogRevision: 7, SchemaGeneration: 8, EngineGeneration: 9},
			Objects: []catalogsnapshot.ObjectInput{{CatalogRevision: 7, Metadata: object}},
			Projections: []catalogsnapshot.RuntimeProjectionInput{{
				CatalogRevision: 7, AppInstallationID: "installation-test", CapabilityID: layoutauthoringv1.CapabilityName,
				Profile: catalogsnapshot.ProjectionLayoutAuthoringV1, ObjectAPINames: []string{object.APIName},
			}},
		}
		if err := manager.WithTransaction(t.Context(), func(ctx context.Context) error {
			return appendStoredLayoutDefinitions(ctx, reader, 7, []*models.ObjectMetadata{object}, &input, true, false)
		}); err != nil {
			return catalogsnapshot.Artifact{}, err
		}
		return catalogsnapshot.CompileCatalogSnapshot(input)
	}
	artifact, err := readPublication()
	if err != nil {
		t.Fatalf("publish historical Layout object aliases through the pinned Core reader: %v", err)
	}
	snapshot, err := catalogsnapshot.OpenCatalogSnapshot(artifact)
	if err != nil {
		t.Fatal(err)
	}
	viewArtifact, err := catalogsnapshot.ProjectRuntimeMetadataView(snapshot, catalogsnapshot.ProjectionKey{
		AppInstallationID: "installation-test", CapabilityID: layoutauthoringv1.CapabilityName,
	})
	if err != nil {
		t.Fatal(err)
	}
	view, err := catalogsnapshot.OpenRuntimeMetadataView(viewArtifact)
	if err != nil {
		t.Fatal(err)
	}
	workspace, ok := view.LayoutAuthoringWorkspace(object.APIName)
	if !ok || len(workspace.Layouts) != 1 || len(workspace.Assignments) != 1 ||
		workspace.Layouts[0].ObjectID != object.APIName || workspace.Assignments[0].ObjectID != object.APIName ||
		!workspace.Layouts[0].IsDefault {
		t.Fatalf("published workspace lost canonical object identity or wildcard default: %#v", workspace)
	}
	if err := manager.WithTransaction(t.Context(), func(ctx context.Context) error {
		aggregate, err := repository.LockLayoutAuthoringAggregate(ctx, object.APIName)
		if err != nil {
			return err
		}
		versions, err := catalogsnapshot.ComputeLayoutAuthoringVersions(
			aggregate.ObjectAPIName, aggregate.OrderedListFields, aggregate.Layouts, aggregate.Assignments,
		)
		if err != nil {
			return err
		}
		if versions.WorkspaceVersion != workspace.WorkspaceVersion ||
			versions.LayoutResourceVersions["default__system_file"] != workspace.Layouts[0].ResourceVersion ||
			versions.AssignmentResourceVersions["assignment-file-default"] != workspace.Assignments[0].ResourceVersion {
			t.Error("published and locked historical-alias versions disagree")
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
	second, err := readPublication()
	if err != nil || second.Digest() != artifact.Digest() {
		t.Fatalf("unchanged stored facts produced a different publication: %v", err)
	}
	for _, table := range []string{"_System_PageLayout", "_System_LayoutAssignment"} {
		var raw string
		if err := db.QueryRowContext(t.Context(), "SELECT ObjectApiName FROM `"+table+"`").Scan(&raw); err != nil {
			t.Fatal(err)
		}
		if raw != "_system_file" {
			t.Fatalf("publication rewrote historical %s identity: %q", table, raw)
		}
		t.Run(table+" rejects Unicode alias", func(t *testing.T) {
			if _, err := db.ExecContext(t.Context(), "UPDATE `"+table+"` SET ObjectApiName = ?", "_ſystem_file"); err != nil {
				t.Fatal(err)
			}
			_, err := readPublication()
			if err == nil || !strings.Contains(err.Error(), "object identity") {
				t.Fatalf("Unicode Layout identity did not fail closed during publication: %v", err)
			}
			if _, err := db.ExecContext(t.Context(), "UPDATE `"+table+"` SET ObjectApiName = ?", raw); err != nil {
				t.Fatal(err)
			}
		})
	}
}
