package bootstrapimpl

import (
	"slices"
	"testing"

	"github.com/nexuscrm/kernel/pkg/schema"
)

func TestConnectorServingAuthoritySystemTablesPublished(t *testing.T) {
	definitions := GetManagedTableDefinitions()
	tableNames := []string{
		"_System_ConnectorServingEpoch",
		"_System_ConnectorServingEpochBinding",
		"_System_ConnectorServingEpochReproducibility",
		"_System_ConnectorServingEpochBindingOwner",
		"_System_ConnectorServingEpochCredentialGeneration",
		"_System_ConnectorAccountServingGate",
		"_System_ConnectorV2Receipt",
		"_System_ConnectorV2ReceiptComponent",
		"_System_ConnectorV2ReceiptAdmissionKey",
	}
	tables := make(map[string]schema.TableDefinition, len(tableNames))
	for _, tableName := range tableNames {
		tables[tableName] = connectorServingAuthorityTable(t, definitions, tableName)
		assertConnectorServingAuthoritySystemTable(t, tables[tableName])
	}

	epoch := tables["_System_ConnectorServingEpoch"]
	assertConnectorServingAuthorityBinaryID(t, epoch, "Id", false)
	assertConnectorServingAuthorityUniqueIndex(t, epoch, "ux_connector_serving_epoch_digest", "EpochDigest")
	assertConnectorServingAuthorityUniqueIndex(t, epoch, "ux_connector_serving_epoch_active_scope", "ActiveScopeDigest")

	binding := tables["_System_ConnectorServingEpochBinding"]
	assertConnectorServingAuthorityBinaryID(t, binding, "Id", false)
	assertConnectorServingAuthorityBinaryID(t, binding, "ServingEpochId", false)
	packPayloadDigest := connectorServingAuthorityColumn(t, binding, "PackPayloadDigest")
	if packPayloadDigest.Type != "CHAR(85)" || packPayloadDigest.Nullable || packPayloadDigest.CollationName != "utf8mb4_bin" {
		t.Fatalf(
			"%s.PackPayloadDigest = type:%q nullable:%t collation:%q, want CHAR(85)/false/utf8mb4_bin",
			binding.TableName,
			packPayloadDigest.Type,
			packPayloadDigest.Nullable,
			packPayloadDigest.CollationName,
		)
	}
	assertConnectorServingAuthorityForeignKey(t, binding, "ServingEpochId", "_System_ConnectorServingEpoch(Id)")
	assertConnectorServingAuthorityUniqueIndex(t, binding, "ux_connector_epoch_binding_ordinal", "ServingEpochId", "BindingOrdinal")
	assertConnectorServingAuthorityUniqueIndex(t, binding, "ux_connector_epoch_binding_identity", "ServingEpochId", "BindingIdentityDigest")

	gate := tables["_System_ConnectorAccountServingGate"]
	assertConnectorServingAuthorityBinaryID(t, gate, "Id", false)
	assertConnectorServingAuthorityBinaryID(t, gate, "ServingEpochId", true)
	assertConnectorServingAuthorityForeignKey(t, gate, "ServingEpochId", "_System_ConnectorServingEpoch(Id)")
	assertConnectorServingAuthorityUniqueIndex(t, gate, "ux_connector_account_gate_scope_account", "ServingScopeDigest", "ConnectorAccountId")

	receipt := tables["_System_ConnectorV2Receipt"]
	receiptProtocol := connectorServingAuthorityColumn(t, receipt, "ReceiptProtocolVersion")
	if receiptProtocol.Type != "VARCHAR(32)" || receiptProtocol.Nullable || receiptProtocol.CollationName != "utf8mb4_bin" {
		t.Fatalf(
			"%s.ReceiptProtocolVersion = type:%q nullable:%t collation:%q, want VARCHAR(32)/false/utf8mb4_bin",
			receipt.TableName,
			receiptProtocol.Type,
			receiptProtocol.Nullable,
			receiptProtocol.CollationName,
		)
	}
	assertConnectorServingAuthorityBinaryID(t, receipt, "Id", false)
	assertConnectorServingAuthorityBinaryID(t, receipt, "ConnectorAccountId", false)
	assertConnectorServingAuthorityBinaryID(t, receipt, "AccountServingGateId", false)
	assertConnectorServingAuthorityBinaryID(t, receipt, "ServingEpochId", false)
	assertConnectorServingAuthorityForeignKey(t, receipt, "AccountServingGateId", "_System_ConnectorAccountServingGate(Id)")
	assertConnectorServingAuthorityForeignKey(t, receipt, "ServingEpochId", "_System_ConnectorServingEpoch(Id)")
	assertConnectorServingAuthorityUniqueIndex(
		t,
		receipt,
		"ux_connector_v2_receipt_admission",
		"ServingScopeDigest",
		"ConnectorAccountId",
		"AdmissionKind",
		"AdmissionAuthorityId",
	)
	receiptComponent := tables["_System_ConnectorV2ReceiptComponent"]
	assertConnectorServingAuthorityBinaryID(t, receiptComponent, "Id", false)
	assertConnectorServingAuthorityBinaryID(t, receiptComponent, "ReceiptId", false)
	assertConnectorServingAuthorityForeignKey(t, receiptComponent, "ReceiptId", "_System_ConnectorV2Receipt(Id)")
	assertConnectorServingAuthorityUniqueIndex(
		t,
		receiptComponent,
		"ux_connector_v2_receipt_component_ordinal",
		"ReceiptId",
		"ComponentOrdinal",
	)

	admissionKey := tables["_System_ConnectorV2ReceiptAdmissionKey"]
	assertConnectorServingAuthorityBinaryID(t, admissionKey, "Id", false)
	assertConnectorServingAuthorityBinaryID(t, admissionKey, "ConnectorAccountId", false)
	assertConnectorServingAuthorityBinaryID(t, admissionKey, "AccountServingGateId", false)
	assertConnectorServingAuthorityBinaryID(t, admissionKey, "ReceiptId", true)
	assertConnectorServingAuthorityForeignKey(t, admissionKey, "AccountServingGateId", "_System_ConnectorAccountServingGate(Id)")
	assertConnectorServingAuthorityForeignKey(t, admissionKey, "ReceiptId", "_System_ConnectorV2Receipt(Id)")
	assertConnectorServingAuthorityUniqueIndex(
		t,
		admissionKey,
		"ux_connector_v2_receipt_key_transport",
		"ConnectorAccountId",
		"IngressChannel",
		"TransportIdempotencyKey",
	)
	assertConnectorServingAuthorityUniqueIndex(t, admissionKey, "ux_connector_v2_receipt_key_receipt", "ReceiptId")
}

func connectorServingAuthorityTable(t *testing.T, definitions []schema.TableDefinition, tableName string) schema.TableDefinition {
	t.Helper()

	for _, definition := range definitions {
		if definition.TableName == tableName {
			return definition
		}
	}
	t.Fatalf("managed Connector serving-authority definition for %s is missing", tableName)
	return schema.TableDefinition{}
}

func assertConnectorServingAuthoritySystemTable(t *testing.T, definition schema.TableDefinition) {
	t.Helper()

	if definition.TableType != "system_core" || definition.Category != "integration" {
		t.Fatalf(
			"%s table type/category = %q/%q, want system_core/integration",
			definition.TableName,
			definition.TableType,
			definition.Category,
		)
	}
	if definition.RequiredReadPermission != "BLOCKED" || definition.RequiredWritePermission != "BLOCKED" {
		t.Fatalf(
			"%s permissions = %q/%q, want BLOCKED/BLOCKED",
			definition.TableName,
			definition.RequiredReadPermission,
			definition.RequiredWritePermission,
		)
	}
}

func connectorServingAuthorityColumn(t *testing.T, definition schema.TableDefinition, columnName string) schema.ColumnDefinition {
	t.Helper()

	for _, column := range definition.Columns {
		if column.Name == columnName {
			return column
		}
	}
	t.Fatalf("%s.%s is missing", definition.TableName, columnName)
	return schema.ColumnDefinition{}
}

func assertConnectorServingAuthorityBinaryID(t *testing.T, definition schema.TableDefinition, columnName string, nullable bool) {
	t.Helper()

	column := connectorServingAuthorityColumn(t, definition, columnName)
	if column.Type != "VARCHAR(255)" || column.Nullable != nullable || column.CollationName != "utf8mb4_bin" {
		t.Fatalf(
			"%s.%s = type:%q nullable:%t collation:%q, want VARCHAR(255)/%t/utf8mb4_bin",
			definition.TableName,
			columnName,
			column.Type,
			column.Nullable,
			column.CollationName,
			nullable,
		)
	}
	if columnName == "Id" && !column.PrimaryKey {
		t.Fatalf("%s.Id primaryKey = false, want true", definition.TableName)
	}
}

func assertConnectorServingAuthorityForeignKey(t *testing.T, definition schema.TableDefinition, columnName, references string) {
	t.Helper()

	for _, foreignKey := range definition.ForeignKeys {
		if foreignKey.Column != columnName {
			continue
		}
		if foreignKey.References != references ||
			!exactManagedAuthorityForeignKeyRuleMatches("RESTRICT", foreignKey.OnDelete) ||
			!exactManagedAuthorityForeignKeyRuleMatches("RESTRICT", foreignKey.OnUpdate) {
			t.Fatalf(
				"%s.%s foreign key = references:%q onDelete:%q onUpdate:%q, want %q with restrictive actions",
				definition.TableName,
				columnName,
				foreignKey.References,
				foreignKey.OnDelete,
				foreignKey.OnUpdate,
				references,
			)
		}
		return
	}
	t.Fatalf("%s.%s foreign key is missing", definition.TableName, columnName)
}

func assertConnectorServingAuthorityUniqueIndex(t *testing.T, definition schema.TableDefinition, indexName string, columns ...string) {
	t.Helper()

	for _, index := range definition.Indices {
		if index.Name != indexName {
			continue
		}
		if !index.Unique || !slices.Equal(index.Columns, columns) {
			t.Fatalf(
				"%s index %s = unique:%t columns:%v, want unique:true columns:%v",
				definition.TableName,
				indexName,
				index.Unique,
				index.Columns,
				columns,
			)
		}
		return
	}
	t.Fatalf("%s unique index %s is missing", definition.TableName, indexName)
}
