package migrate

import (
	"github.com/pingcap/log"
	"github.com/tidbcloud/serverless-service/internal/domain/entity"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

// 202606071200 adds configurable sharing scope to Essential CDC newarch
// shard tables. The original newarch migration has already shipped, so
// this migration alters the existing schema instead of editing the old
// record. Newarch is not yet serving production traffic; default
// global/global values keep staging or test rows valid while the service
// starts writing explicit scope/key values.
//
// Table names must match the names GORM derives from the entity structs.
// TiCDCChangefeedResource -> ti_cdc_changefeed_resources,
// TiCDCCluster            -> ti_cdc_clusters,
// KernelTiCDCChangefeed   -> kernel_ti_cdc_changefeeds.
// (Note: "ti_cdc_clusters", NOT "ticdc_clusters".)
var _ = AddDBMigrateRecord(
	"202606071200",
	func(db *gorm.DB) error {
		if err := db.AutoMigrate(
			&entity.TiCDCChangefeedResource{},
			&entity.KernelTiCDCChangefeed{},
			&entity.TiCDCCluster{},
		); err != nil {
			log.Error("ensure cdc newarch tables failed", zap.Error(err))
			return err
		}
		tables := []string{
			"ti_cdc_changefeed_resources",
			"ti_cdc_clusters",
			"kernel_ti_cdc_changefeeds",
		}
		for _, table := range tables {
			if err := addCDCNewArchShareColumnIfMissing(db, table, "share_scope", "kubernetes", "VARCHAR(32) NOT NULL DEFAULT 'global'"); err != nil {
				return err
			}
			if err := addCDCNewArchShareColumnIfMissing(db, table, "share_key", "share_scope", "VARCHAR(128) NOT NULL DEFAULT 'global'"); err != nil {
				return err
			}
		}
		if err := replaceCDCNewArchShardIndex(
			db,
			"ti_cdc_changefeed_resources",
			"idx_ticdc_resource_shard",
			"ADD INDEX `idx_ticdc_resource_shard` (`cloud_provider`, `region`, `kubernetes`, `share_scope`, `share_key`)",
		); err != nil {
			return err
		}
		if err := replaceCDCNewArchShardIndex(
			db,
			"ti_cdc_clusters",
			"udx_ticdc_cluster_shard",
			"ADD UNIQUE INDEX `udx_ticdc_cluster_shard` (`cloud_provider`, `region`, `kubernetes`, `share_scope`, `share_key`)",
		); err != nil {
			return err
		}
		if err := replaceCDCNewArchShardIndex(
			db,
			"kernel_ti_cdc_changefeeds",
			"idx_kernel_ticdc_changefeed_shard",
			"ADD INDEX `idx_kernel_ticdc_changefeed_shard` (`cloud_provider`, `region`, `kubernetes`, `share_scope`, `share_key`)",
		); err != nil {
			return err
		}
		return nil
	},
)

func addCDCNewArchShareColumnIfMissing(db *gorm.DB, table, column, after, definition string) error {
	if db.Migrator().HasColumn(table, column) {
		return nil
	}
	sql := "ALTER TABLE `" + table + "` ADD COLUMN `" + column + "` " + definition + " AFTER `" + after + "`"
	if err := db.Exec(sql).Error; err != nil {
		log.Error("add cdc newarch share column failed",
			zap.String("sql", sql), zap.Error(err))
		return err
	}
	return nil
}

func replaceCDCNewArchShardIndex(db *gorm.DB, table, index, addIndex string) error {
	if db.Migrator().HasIndex(table, index) {
		dropSQL := "ALTER TABLE `" + table + "` DROP INDEX `" + index + "`"
		if err := db.Exec(dropSQL).Error; err != nil {
			log.Error("drop cdc newarch shard index failed",
				zap.String("sql", dropSQL), zap.Error(err))
			return err
		}
	}
	addSQL := "ALTER TABLE `" + table + "` " + addIndex
	if err := db.Exec(addSQL).Error; err != nil {
		log.Error("add cdc newarch shard index failed",
			zap.String("sql", addSQL), zap.Error(err))
		return err
	}
	return nil
}
