package common

import (
	"strings"

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

// GetInstanceCpuGeneration returns the CPU generation for a given component tier unit.
// Currently, only AWS ARM64 instance CPU generations are returned (GRAVITON2 | GRAVITON4).
// For all other cases, CPU_GENERATION_UNSPECIFIED is returned.
// In the long run, we should store cpu generation in the instance_types table.
func GetInstanceCpuGeneration(
	componentTierUnit *schema.ComponentTierUnit,
) (globaldedicatedv1.InstanceMu_CpuGeneration, bizerr.BizError) {
	cloudProviderCvt, err := enum.FromString[globalcommonv1.CloudProvider_Name](componentTierUnit.Provider.Name)
	if err != nil {
		return globaldedicatedv1.InstanceMu_CPU_GENERATION_UNSPECIFIED, bizerr.WrapError(err, "convert cloud provider")
	}
	cloudProvider := globalcommonv1.CloudProvider_Name(cloudProviderCvt)
	cpuArchCvt, err := enum.FromString[globaldedicatedv1.InstanceMu_CpuArch](componentTierUnit.InstanceType.CpuArch)
	if err != nil {
		return globaldedicatedv1.InstanceMu_CPU_GENERATION_UNSPECIFIED, bizerr.WrapError(err, "convert cpu arch")
	}
	cpuArch := globaldedicatedv1.InstanceMu_CpuArch(cpuArchCvt)
	instanceType := componentTierUnit.InstanceType.InstanceType

	if cloudProvider == globalcommonv1.CloudProvider_AWS && cpuArch == globaldedicatedv1.InstanceMu_ARM64 {
		if strings.Contains(instanceType, "6g.") {
			return globaldedicatedv1.InstanceMu_GRAVITON2, nil
		}
		if strings.Contains(instanceType, "4g.") {
			return globaldedicatedv1.InstanceMu_GRAVITON2, nil
		}
		if strings.Contains(instanceType, "8g.") {
			return globaldedicatedv1.InstanceMu_GRAVITON4, nil
		}
		return globaldedicatedv1.InstanceMu_CPU_GENERATION_UNSPECIFIED, bizerr.New(
			bizerr.ErrCodeUnknown,
			"failed to get instance CPU generation for instance type %s",
			instanceType,
		)
	}

	if cloudProvider == globalcommonv1.CloudProvider_GCP {
		parts := strings.Split(instanceType, "-")
		if instanceType == "" || parts[0] == "" {
			return globaldedicatedv1.InstanceMu_CPU_GENERATION_UNSPECIFIED, bizerr.New(
				bizerr.ErrCodeUnknown,
				"failed to parse GCP instance type %s",
				instanceType,
			)
		}
		series := strings.ToUpper(parts[0])

		// 4th generation
		intel4thGen := map[string]bool{"N4": true, "C4": true}
		amd4thGen := map[string]bool{"C4D": true}
		arm4thGen := map[string]bool{"C4A": true}

		// 2nd generation
		// intel2ndGen := map[string]bool{"N2": true, "C2": true}
		amd2ndGen := map[string]bool{"N2D": true}

		switch cpuArch {
		case globaldedicatedv1.InstanceMu_AMD64:
			if intel4thGen[series] {
				return globaldedicatedv1.InstanceMu_GENERATION4_INTEL_XEON, nil
			}
			if amd4thGen[series] {
				return globaldedicatedv1.InstanceMu_GENERATION4_AMD_EPYC, nil
			}
			if amd2ndGen[series] {
				return globaldedicatedv1.InstanceMu_GENERATION2_AMD_EPYC, nil
			}
			// if intel2ndGen[series] {
			// 	return globaldedicatedv1.InstanceMu_GENERATION2_INTEL_XEON, nil
			// }
		case globaldedicatedv1.InstanceMu_ARM64:
			if arm4thGen[series] {
				return globaldedicatedv1.InstanceMu_GENERATION4_AXION, nil
			}
		}
		return globaldedicatedv1.InstanceMu_CPU_GENERATION_UNSPECIFIED, nil
	}

	return globaldedicatedv1.InstanceMu_CPU_GENERATION_UNSPECIFIED, nil
}
