package migration

import (
	"time"

	"github.com/samber/lo"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"

	globaldedicatedv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/dedicated/v1"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/infra/repoimpl/schema"
)

// Add 32c64g graviton4 pd sku and 32c128g graviton4 tikv skus
var _ = AddDBMigrateRecord(
	"202508081700",
	func(db *gorm.DB) error {
		timestamp := time.Now()

		return db.Transaction(func(tx *gorm.DB) error {
			// Fetch the AWS provider.
			var provider *schema.Provider
			if err := db.Where("name = ?", "aws").First(&provider).Error; err != nil {
				return err
			}

			// Fetch instance types.
			var instanceTypes []*schema.InstanceType
			if err := db.Where("instance_type IN ?", []string{"c8g.8xlarge", "m8g.8xlarge"}).Find(&instanceTypes).Error; err != nil {
				return err
			}
			instanceTypeMap := lo.SliceToMap(
				instanceTypes,
				func(i *schema.InstanceType) (string, *schema.InstanceType) {
					return i.InstanceType, i
				},
			)

			// Fetch storage for io2 and gp3 volumes.
			var io2Storage, gp3Storage *schema.StorageTemplate
			if err := db.Where("volume_type = ?", "io2").First(&io2Storage).Error; err != nil {
				return err
			}
			if err := db.Where("volume_type = ?", "gp3").First(&gp3Storage).Error; err != nil {
				return err
			}

			// Add tikv skus.
			var tikvSpu32c128gNew *schema.ComponentTier
			{
				tikvSpusToCreate := make([]*schema.ComponentTier, 0, 1)
				tikvSkus := make([]*schema.ComponentTierUnit, 0, 3)

				tikvSpu32c128gNew = &schema.ComponentTier{
					Key:           "32C128G:DEPLOY_TYPE_DEDICATED:COMPONENT_TYPE_TIKV",
					ComponentType: "tikv",
					DisplayName:   "32 vCPU, 128 GiB",
					CPUNum:        32,
					MemorySizeGi:  128,
				}
				tikvSpusToCreate = append(tikvSpusToCreate, tikvSpu32c128gNew)
				if err := tx.Clauses(clause.OnConflict{
					Columns:   []clause.Column{{Name: "key"}},
					UpdateAll: true,
				}).Create(tikvSpusToCreate).Error; err != nil {
					return err
				}

				tikvSkus = append(tikvSkus,
					&schema.ComponentTierUnit{
						Key:                    "aws:tikv:m8g.8xlarge:gp3:16000:1000:32c64g-pd:Standard",
						Priority:               999,
						ComponentType:          "tikv",
						ProviderId:             uint64(provider.ID),
						ComponentTierId:        uint64(tikvSpu32c128gNew.ID),
						InstanceTypeId:         uint64(instanceTypeMap["m8g.8xlarge"].ID),
						DefaultNodeNum:         3,
						StorageTemplateId:      lo.ToPtr(uint64(gp3Storage.ID)),
						MinStorageGi:           200,
						MaxStorageGi:           4096,
						DefaultStorageGi:       500,
						MaxIops:                16000,
						MinIops:                3000,
						IopsPerGi:              4,
						MaxThroughPut:          1000,
						MinThroughPut:          125,
						ThroughputMibpsPerGi:   0.5,
						ThroughputMibpsPerIops: 0.046875,
						RaftStorageTemplateId:  lo.ToPtr(uint64(gp3Storage.ID)),
						RaftDefaultStorageGi:   40,
						RaftMinStorageGi:       40,
						RaftMaxStorageGi:       40,
						RaftDefaultIops:        3000,
						RaftMaxIops:            3000,
						RaftMinIops:            3000,
						RaftDefaultThroughPut:  125,
						RaftMaxThroughPut:      125,
						RaftMinThroughPut:      125,
					},
					&schema.ComponentTierUnit{
						Key:                    "aws:tikv:m8g.8xlarge:gp3:16000:1000:32c64g-pd:Performance",
						Priority:               999,
						ComponentType:          "tikv",
						ProviderId:             uint64(provider.ID),
						ComponentTierId:        uint64(tikvSpu32c128gNew.ID),
						InstanceTypeId:         uint64(instanceTypeMap["m8g.8xlarge"].ID),
						DefaultNodeNum:         3,
						StorageTemplateId:      lo.ToPtr(uint64(gp3Storage.ID)),
						MinStorageGi:           200,
						MaxStorageGi:           4096,
						DefaultStorageGi:       500,
						MaxIops:                16000,
						MinIops:                3000,
						IopsPerGi:              4,
						MaxThroughPut:          1000,
						MinThroughPut:          125,
						ThroughputMibpsPerGi:   0.5,
						ThroughputMibpsPerIops: 0.046875,
						RaftStorageTemplateId:  lo.ToPtr(uint64(io2Storage.ID)),
						RaftDefaultStorageGi:   40,
						RaftMinStorageGi:       40,
						RaftMaxStorageGi:       40,
						RaftDefaultIops:        4000,
						RaftMaxIops:            4000,
						RaftMinIops:            4000,
					},
					&schema.ComponentTierUnit{
						Key:               "aws:tikv:m8g.8xlarge:io2:8000:0:32c64g-pd",
						Priority:          999,
						ComponentType:     "tikv",
						ProviderId:        uint64(provider.ID),
						ComponentTierId:   uint64(tikvSpu32c128gNew.ID),
						InstanceTypeId:    uint64(instanceTypeMap["m8g.8xlarge"].ID),
						DefaultNodeNum:    3,
						StorageTemplateId: lo.ToPtr(uint64(io2Storage.ID)),
						MinStorageGi:      200,
						MaxStorageGi:      4096,
						DefaultStorageGi:  500,
						DefaultIops:       8000,
						MaxIops:           8000,
						MinIops:           8000,
					})

				for _, tikvSku := range tikvSkus {
					tikvSku.CreatedAt = timestamp
					tikvSku.UpdatedAt = timestamp
					if err := tx.Clauses(clause.OnConflict{
						Columns:   []clause.Column{{Name: "key"}},
						UpdateAll: true,
					}).Create(tikvSku).Error; err != nil {
						return err
					}
				}
			}

			// Add pd skus
			var pdSku32c64g *schema.ComponentTierUnit
			{
				pdSpu32c64g := &schema.ComponentTier{
					Key:           "32C64G:DEPLOY_TYPE_DEDICATED:COMPONENT_TYPE_PD",
					ComponentType: "pd",
					DisplayName:   "32 vCPU, 64 GiB",
					CPUNum:        32,
					MemorySizeGi:  64,
				}
				if err := tx.Clauses(clause.OnConflict{
					Columns:   []clause.Column{{Name: "key"}},
					UpdateAll: true,
				}).Create(pdSpu32c64g).Error; err != nil {
					return err
				}

				pdSku32c64g = &schema.ComponentTierUnit{
					Key:               "aws:pd:c8g.8xlarge:gp3:3000:125",
					Priority:          999,
					ComponentType:     "pd",
					ProviderId:        uint64(provider.ID),
					ComponentTierId:   uint64(pdSpu32c64g.ID),
					InstanceTypeId:    uint64(instanceTypeMap["c8g.8xlarge"].ID),
					DefaultNodeNum:    3,
					StorageTemplateId: lo.ToPtr(uint64(gp3Storage.ID)),
					MinStorageGi:      20,
					MaxStorageGi:      20,
					DefaultStorageGi:  20,
					DefaultIops:       3000,
					MaxIops:           3000,
					MinIops:           3000,
					DefaultThroughPut: lo.ToPtr(uint32(125)),
					MaxThroughPut:     125,
					MinThroughPut:     125,
				}
				pdSku32c64g.CreatedAt = timestamp
				pdSku32c64g.UpdatedAt = timestamp
				if err := tx.Clauses(clause.OnConflict{
					Columns:   []clause.Column{{Name: "key"}},
					UpdateAll: true,
				}).Create(pdSku32c64g).Error; err != nil {
					return err
				}
			}

			// Add pd tikv mappings
			pdTikvMappings := []*schema.TierUnitCondition{
				{
					ComponentTierUnitId: uint64(pdSku32c64g.ID),
					Key:                 globaldedicatedv1.Sku_Condition_ATTACH_TIERUNIT.String(),
					Operator:            globaldedicatedv1.Sku_Condition_IN.String(),
					Values: `[
"aws:tikv:m8g.8xlarge:gp3:16000:1000:32c64g-pd:Standard",
"aws:tikv:m8g.8xlarge:gp3:16000:1000:32c64g-pd:Performance",
"aws:tikv:m8g.8xlarge:io2:8000:0:32c64g-pd"
]`,
				},
			}

			for _, pdTikvMapping := range pdTikvMappings {
				pdTikvMapping.CreatedAt = timestamp
				pdTikvMapping.UpdatedAt = timestamp
				if err := tx.Clauses(clause.OnConflict{
					Columns:   []clause.Column{{Name: "key"}, {Name: "component_tier_unit_id"}},
					UpdateAll: true,
				}).Create(pdTikvMapping).Error; err != nil {
					return err
				}
			}

			return nil
		})
	},
)
