//go:build integration

package controlplane

import (
	"context"
	"testing"

	"github.com/nexuscrm/db"
	"github.com/nexuscrm/shared/pkg/constants"
)

func TestEnsureL0SchemaDDLRejectsDestructiveResidueBeforeMetadataAuthority(t *testing.T) {
	ctx := context.Background()
	cfg, cleanup := newTemporaryIntegrationDatabase(t)
	defer cleanup()
	setDatabaseEnvFromConfig(t, cfg)

	conn := openIntegrationConnection(t, cfg)
	conn, err := EnsureL0SchemaDDL(ctx, conn)
	if err != nil {
		t.Fatalf("initial EnsureL0SchemaDDL on a clean database: %v", err)
	}
	assertPermissionStateSingletonCount(t, ctx, conn, 0)

	result, err := conn.DB().ExecContext(
		ctx,
		"UPDATE _System_Table SET IsDeleted = 1 WHERE TableName = ?",
		constants.TableRequestCapture,
	)
	if err != nil {
		t.Fatalf("mark DDL-only table drop-pending: %v", err)
	}
	if affected, err := result.RowsAffected(); err != nil || affected != 1 {
		t.Fatalf("drop-pending registry rows = %d, err = %v; want 1", affected, err)
	}

	if _, err = EnsureL0SchemaDDL(ctx, conn); err == nil {
		t.Fatal("EnsureL0SchemaDDL accepted destructive residue in the additive-only phase")
	}

	assertPermissionStateSingletonCount(t, ctx, conn, 0)
	var physicalTables, deletedRegistryRows int
	if err := conn.DB().QueryRowContext(
		ctx,
		"SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?",
		constants.TableRequestCapture,
	).Scan(&physicalTables); err != nil {
		t.Fatalf("read preserved physical table: %v", err)
	}
	if physicalTables != 1 {
		t.Fatalf("physical tables after rejected additive apply = %d, want 1", physicalTables)
	}
	if err := conn.DB().QueryRowContext(
		ctx,
		"SELECT COUNT(*) FROM _System_Table WHERE TableName = ? AND IsDeleted = 1",
		constants.TableRequestCapture,
	).Scan(&deletedRegistryRows); err != nil {
		t.Fatalf("read preserved destructive residue: %v", err)
	}
	if deletedRegistryRows != 1 {
		t.Fatalf("drop-pending registry rows after rejected additive apply = %d, want 1", deletedRegistryRows)
	}
}

func TestInitializeSchemaOwnsPermissionStatePrerequisite(t *testing.T) {
	ctx := context.Background()
	cfg, cleanup := newTemporaryIntegrationDatabase(t)
	defer cleanup()

	conn := openIntegrationConnection(t, cfg)
	defer conn.Close()
	if err := schemaProvisioner.InitializeSchema(conn); err != nil {
		t.Fatalf("InitializeSchema on a clean database: %v", err)
	}
	assertPermissionStateSingletonCount(t, ctx, conn, 1)
}

func TestApplyL0ManagedMetadataOwnsPermissionStatePrerequisite(t *testing.T) {
	ctx := context.Background()
	cfg, cleanup := newTemporaryIntegrationDatabase(t)
	defer cleanup()
	setDatabaseEnvFromConfig(t, cfg)

	conn := openIntegrationConnection(t, cfg)
	conn, err := ApplyL0ManagedMetadata(ctx, conn)
	if err != nil {
		t.Fatalf("ApplyL0ManagedMetadata on a clean database: %v", err)
	}
	defer conn.Close()
	assertPermissionStateSingletonCount(t, ctx, conn, 1)
}

func TestInitL0InitializesPermissionStateBeforePermissionWriters(t *testing.T) {
	ctx := context.Background()
	cfg, cleanup := newTemporaryIntegrationDatabase(t)
	defer cleanup()
	setDatabaseEnvFromConfig(t, cfg)

	conn := openIntegrationConnection(t, cfg)
	if err := InitL0(ctx, conn); err != nil {
		t.Fatalf("InitL0 on a clean database: %v", err)
	}

	checkConn := openIntegrationConnection(t, cfg)
	defer checkConn.Close()
	assertPermissionStateSingletonCount(t, ctx, checkConn, 1)
}

func TestApplyMetadataInitializesPermissionStateBeforePackWriters(t *testing.T) {
	ctx := context.Background()
	cfg, cleanup := newTemporaryIntegrationDatabase(t)
	defer cleanup()
	setDatabaseEnvFromConfig(t, cfg)

	conn := openIntegrationConnection(t, cfg)
	conn, err := ApplyMetadata(ctx, conn)
	if err != nil {
		t.Fatalf("ApplyMetadata on a clean database: %v", err)
	}
	defer func() {
		_ = conn.Close()
	}()

	assertPermissionStateSingletonCount(t, ctx, conn, 1)

	conn, err = ApplyMetadata(ctx, conn)
	if err != nil {
		t.Fatalf("second ApplyMetadata on the same database: %v", err)
	}
	assertPermissionStateSingletonCount(t, ctx, conn, 1)
}

func assertPermissionStateSingletonCount(
	t *testing.T,
	ctx context.Context,
	conn *database.TiDBConnection,
	want int,
) {
	t.Helper()

	var count int
	if err := conn.DB().QueryRowContext(
		ctx,
		"SELECT COUNT(*) FROM _System_PermissionStateVersion WHERE SingletonKey = 1",
	).Scan(&count); err != nil {
		t.Fatalf("read permission state singleton: %v", err)
	}
	if count != want {
		t.Fatalf("permission state singleton count = %d, want %d", count, want)
	}
}
