package serving

import (
	"context"
	"database/sql"
	"fmt"
)

const (
	v2ReceiptTable             = "_System_ConnectorV2Receipt"
	v2ReceiptComponentTable    = "_System_ConnectorV2ReceiptComponent"
	v2ReceiptAdmissionKeyTable = "_System_ConnectorV2ReceiptAdmissionKey"
)

var v2ReceiptSchema = servingTableSchema{
	name: v2ReceiptTable,
	columns: []expectedServingColumn{
		{name: "Id", columnType: "varchar(255)", collation: "utf8mb4_bin"},
		{name: "ReceiptProtocolVersion", columnType: "varchar(32)", collation: "utf8mb4_bin"},
		{name: "ServingScopeDigest", columnType: "char(64)", collation: "utf8mb4_bin"},
		{name: "ConnectorAccountId", columnType: "varchar(255)", collation: "utf8mb4_bin"},
		{name: "AccountServingGateId", columnType: "varchar(255)", collation: "utf8mb4_bin"},
		{name: "AccountServingFenceToken", columnType: "bigint(20)"},
		{name: "ServingEpochId", columnType: "varchar(255)", collation: "utf8mb4_bin"},
		{name: "ServingEpochDigest", columnType: "char(71)", collation: "utf8mb4_bin"},
		{name: "AdmissionKind", columnType: "varchar(32)", collation: "utf8mb4_bin"},
		{name: "AdmissionAuthorityId", columnType: "varchar(255)", collation: "utf8mb4_bin"},
		{name: "PayloadCiphertextProtocolVersion", columnType: "varchar(255)", collation: "utf8mb4_bin"},
		{name: "PayloadCiphertext", columnType: "mediumblob"},
		{name: "PayloadDigest", columnType: "char(71)", collation: "utf8mb4_bin"},
		{name: "PayloadSizeBytes", columnType: "bigint(20)"},
		{name: "ReceiptComponentCount", columnType: "bigint(20)"},
		{name: "CreatedDate", columnType: "datetime(6)", hasDefault: true, columnDefault: "CURRENT_TIMESTAMP(6)", allowDefaultGenerated: true},
		{name: "LastModifiedDate", columnType: "datetime(6)", hasDefault: true, columnDefault: "CURRENT_TIMESTAMP(6)", allowDefaultGenerated: true},
	},
	indexes: []expectedServingIndex{
		{name: "PRIMARY", unique: true, columns: []string{"Id"}},
		{name: "ux_connector_v2_receipt_admission", unique: true, columns: []string{"ServingScopeDigest", "ConnectorAccountId", "AdmissionKind", "AdmissionAuthorityId"}},
		{name: "idx_connector_v2_receipt_account", columns: []string{"ConnectorAccountId", "Id"}},
		{name: "idx_connector_v2_receipt_epoch", columns: []string{"ServingEpochId", "Id"}},
		{name: "idx_connector_v2_receipt_gate", columns: []string{"AccountServingGateId", "Id"}},
	},
	foreignKeys: []expectedServingForeignKey{
		{column: "AccountServingGateId", referencedTable: accountServingGateTable, referencedColumn: "Id"},
		{column: "ServingEpochId", referencedTable: servingEpochTable, referencedColumn: "Id"},
	},
}

var v2ReceiptAdmissionKeySchema = servingTableSchema{
	name: v2ReceiptAdmissionKeyTable,
	columns: []expectedServingColumn{
		{name: "Id", columnType: "varchar(255)", collation: "utf8mb4_bin"},
		{name: "AdmissionKeyProtocolVersion", columnType: "varchar(255)", collation: "utf8mb4_bin"},
		{name: "ServingScopeDigest", columnType: "char(64)", collation: "utf8mb4_bin"},
		{name: "ConnectorAccountId", columnType: "varchar(255)", collation: "utf8mb4_bin"},
		{name: "AccountServingGateId", columnType: "varchar(255)", collation: "utf8mb4_bin"},
		{name: "IngressChannel", columnType: "varchar(64)", collation: "utf8mb4_bin"},
		{name: "TransportIdempotencyKey", columnType: "varchar(255)", collation: "utf8mb4_bin"},
		{name: "AuthorizedPayloadDigest", columnType: "char(71)", collation: "utf8mb4_bin"},
		{name: "Disposition", columnType: "varchar(32)", collation: "utf8mb4_bin"},
		{name: "ReceiptId", columnType: "varchar(255)", nullable: true, collation: "utf8mb4_bin"},
		{name: "PredecessorRefProtocolVersion", columnType: "varchar(255)", nullable: true, collation: "utf8mb4_bin"},
		{name: "PredecessorRef", columnType: "mediumblob", nullable: true},
		{name: "PredecessorRefDigest", columnType: "char(71)", nullable: true, collation: "utf8mb4_bin"},
		{name: "CreatedDate", columnType: "datetime(6)", hasDefault: true, columnDefault: "CURRENT_TIMESTAMP(6)", allowDefaultGenerated: true},
		{name: "LastModifiedDate", columnType: "datetime(6)", hasDefault: true, columnDefault: "CURRENT_TIMESTAMP(6)", allowDefaultGenerated: true},
	},
	indexes: []expectedServingIndex{
		{name: "PRIMARY", unique: true, columns: []string{"Id"}},
		{name: "ux_connector_v2_receipt_key_transport", unique: true, columns: []string{"ConnectorAccountId", "IngressChannel", "TransportIdempotencyKey"}},
		{name: "ux_connector_v2_receipt_key_receipt", unique: true, columns: []string{"ReceiptId"}},
		{name: "idx_connector_v2_receipt_key_gate", columns: []string{"AccountServingGateId", "Disposition", "Id"}},
	},
	foreignKeys: []expectedServingForeignKey{
		{column: "AccountServingGateId", referencedTable: accountServingGateTable, referencedColumn: "Id"},
		{column: "ReceiptId", referencedTable: v2ReceiptTable, referencedColumn: "Id"},
	},
}

var v2ReceiptComponentSchema = servingTableSchema{
	name: v2ReceiptComponentTable,
	columns: []expectedServingColumn{
		{name: "Id", columnType: "varchar(255)", collation: "utf8mb4_bin"},
		{name: "ComponentProtocolVersion", columnType: "varchar(255)", collation: "utf8mb4_bin"},
		{name: "ReceiptId", columnType: "varchar(255)", collation: "utf8mb4_bin"},
		{name: "ComponentOrdinal", columnType: "int(11)"},
		{name: "PayloadCiphertextProtocolVersion", columnType: "varchar(255)", collation: "utf8mb4_bin"},
		{name: "PayloadCiphertext", columnType: "mediumblob"},
		{name: "PayloadDigest", columnType: "char(71)", collation: "utf8mb4_bin"},
		{name: "PayloadSizeBytes", columnType: "bigint(20)"},
		{name: "CreatedDate", columnType: "datetime(6)", hasDefault: true, columnDefault: "CURRENT_TIMESTAMP(6)", allowDefaultGenerated: true},
		{name: "LastModifiedDate", columnType: "datetime(6)", hasDefault: true, columnDefault: "CURRENT_TIMESTAMP(6)", allowDefaultGenerated: true},
	},
	indexes: []expectedServingIndex{
		{name: "PRIMARY", unique: true, columns: []string{"Id"}},
		{name: "ux_connector_v2_receipt_component_ordinal", unique: true, columns: []string{"ReceiptId", "ComponentOrdinal"}},
	},
	foreignKeys: []expectedServingForeignKey{
		{column: "ReceiptId", referencedTable: v2ReceiptTable, referencedColumn: "Id"},
	},
}

var ingressReceiptAuthoritySchemas = []servingTableSchema{
	{
		name:    servingEpochTable,
		columns: servingEpochColumns,
		indexes: servingEpochIndexes,
	},
	accountServingGateSchema,
	v2ReceiptSchema,
	v2ReceiptComponentSchema,
	v2ReceiptAdmissionKeySchema,
}

// verifyIngressReceiptAuthoritySchema is separate from Repository.VerifySchema:
// prepared-epoch authoring must not depend on ingress authority tables. The
// physical schema remains catalog-owned and this check is strictly read-only.
func verifyIngressReceiptAuthoritySchema(ctx context.Context, db *sql.DB) error {
	if ctx == nil || db == nil {
		return ingressReceiptSchemaError("database or context is unavailable", nil)
	}
	for _, table := range ingressReceiptAuthoritySchemas {
		if err := verifyServingColumns(ctx, db, table.name, table.columns); err != nil {
			return ingressReceiptSchemaError(fmt.Sprintf("verify %s columns", table.name), err)
		}
	}
	for _, table := range ingressReceiptAuthoritySchemas {
		if err := verifyServingIndexes(ctx, db, table.name, table.indexes); err != nil {
			return ingressReceiptSchemaError(fmt.Sprintf("verify %s indexes", table.name), err)
		}
	}
	for _, table := range ingressReceiptAuthoritySchemas {
		if err := verifyServingForeignKeys(ctx, db, table.name, table.foreignKeys); err != nil {
			return ingressReceiptSchemaError(fmt.Sprintf("verify %s foreign keys", table.name), err)
		}
	}
	return nil
}

func ingressReceiptSchemaError(operation string, cause error) error {
	if cause == nil {
		return fmt.Errorf("%w: %w: %s", ErrSchemaUnavailable, ErrIngressReceiptSchemaUnavailable, operation)
	}
	return fmt.Errorf("%w: %w: %s: %w", ErrSchemaUnavailable, ErrIngressReceiptSchemaUnavailable, operation, cause)
}
