package main

import (
	"path/filepath"

	"github.com/samber/lo"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/tidbcloud/cluster-tier-config/script/model"
)

func newTierIntegrityChecker() *cobra.Command {
	var (
		enableWhitelist bool
	)
	cmd := &cobra.Command{
		Use:   "check-tier-integrity",
		Short: "check integrity of tiers",
		Run: func(cmd *cobra.Command, args []string) {
			checkTierIntegrity(enableWhitelist)
		},
	}
	cmd.Flags().BoolVar(&enableWhitelist, "enable-whitelist", true, "whether enable whitelist")

	return cmd
}

func checkTierIntegrity(enableWhitelist bool) {
	fullPath, _ := filepath.Abs(yamlDir)
	logrus.Infof("run tier integrity checker in %s", fullPath)

	tiers := readTiers(yamlDir)

	checkTierCpuArch(tiers)
	checkX86First(tiers)
}

// checkTierCpuArch check whether all tiers on AWS for dedicated cluster have both ARM and X86 tier units.
func checkTierCpuArch(tiers []*model.TierYaml) {
	var missingSomeArch bool
	for _, each := range tiers {
		tierKey := model.BuildTierKey(each.Name, each.DeployType, each.ComponentType)

		if each.DeployType == "shared" {
			logrus.Debugf("ignore check for shared tier")
			continue
		}

		// skip for pd
		if each.ComponentType == "pd" {
			logrus.Debugf("ignore check for PD component")
			continue
		}

		var (
			hasArm = map[string]bool{}
			hasX86 = map[string]bool{}
		)
		for provider, mappings := range each.TierUnitMap {
			if provider == model.CloudProviderGCP {
				logrus.Debugf("ignore for GCP provider")
				continue
			}

			for _, mapping := range mappings {
				// non-standard tier unit mapping, skip
				if !(len(mapping.TenantIds) == 1 && mapping.TenantIds[0] == 0) {
					logrus.Debugf("ignore for non-standard mapping")
					continue
				}

				parsedTierUnitKey := model.ParseTierUnitKey(mapping.TierUnitKey)
				if model.IsAwsArm(parsedTierUnitKey.ComputeType) {
					for _, region := range mapping.Regions {
						hasArm[region] = true
					}
				} else {
					for _, region := range mapping.Regions {
						hasX86[region] = true
					}
				}
			}
		}

		armRegions := lo.Keys(hasArm)
		x86Regions := lo.Keys(hasX86)
		for _, region := range armRegions {
			if !hasX86[region] {
				logrus.Warnf("tier(%s) miss X86 tier unit in region(%s)", tierKey, region)
				missingSomeArch = true
			}
		}

		for _, region := range x86Regions {
			if !hasArm[region] {
				logrus.Warnf("tier(%s) miss ARM tier unit in region(%s)", tierKey, region)
				missingSomeArch = true
			}
		}
	}

	if missingSomeArch {
		logrus.Fatalf("some tiers don't have required tier units")
	} else {
		logrus.Infof("all check checkTierCpuArch passwd\n")
	}
}

// checkX86First check whether x86 tier unit first in tier.tierUnitMap
func checkX86First(tiers []*model.TierYaml) {
	var someFailure bool
	for _, each := range tiers {
		tierKey := model.BuildTierKey(each.Name, each.DeployType, each.ComponentType)

		if each.DeployType == "shared" {
			logrus.Debugf("ignore check for shared tier")
			continue
		}

		// skip for pd
		if each.ComponentType == "pd" {
			logrus.Debugf("ignore check for PD component")
			continue
		}

		x86AtFirst := true
		for _, mappings := range each.TierUnitMap {
			for _, mapping := range mappings {
				// non-standard tier unit mapping, skip
				if !(len(mapping.TenantIds) == 1 && mapping.TenantIds[0] == 0) {
					logrus.Debugf("ignore for non-standard mapping")
					continue
				}

				parsedTierUnitKey := model.ParseTierUnitKey(mapping.TierUnitKey)
				if model.IsAwsArm(parsedTierUnitKey.ComputeType) {
					x86AtFirst = false
				}
				break // stop looping
			}
		}

		if !x86AtFirst {
			logrus.Warnf("tier(%s) is NOT configured as X86 first", tierKey)
			someFailure = true
		}
	}

	if someFailure {
		logrus.Fatalf("some tiers are NOT configured as X86 first")
	} else {
		logrus.Infof("all check checkX86First passwd\n")
	}
}
