package utils

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"strconv"
	"strings"

	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
)

type Namer struct {
	tenantID  string
	projectID string
	clusterID string
	Region    string
	Env       string
}

func NewNamer(tenantID, projectID, clusterID, region, env string) *Namer {
	return &Namer{
		tenantID:  tenantID,
		projectID: projectID,
		clusterID: clusterID,
		Region:    region,
		Env:       env,
	}
}

func NewNamerWithClusterID(clusterID, region, env string) *Namer {
	return &Namer{
		clusterID: clusterID,
		Region:    region,
		Env:       env,
	}
}

func (n *Namer) GetClusterID() string {
	return n.clusterID
}

func (n *Namer) GetProjectID() string {
	return n.projectID
}

func (n *Namer) GetTenantID() string {
	return n.tenantID
}

func (n *Namer) GetProjectLabelKey() string {
	return genProjectLabelKey(n.projectID)
}

func (n *Namer) GetTenantLabelKey() string {
	return genTenantLabelKey(n.tenantID)
}

func (n *Namer) GetClusterLabelKey() string {
	return fmt.Sprintf("%s%s", v1alpha1.ClusterIDKeyPrefix, n.clusterID)
}

// GetUniqueName returns a unique name.
// the name is generated by md5(tenantID-projectID-clusterID)
func (n *Namer) GetUniqueName() string {
	// md5 is not unique, but it's enough for now
	return MD5(fmt.Sprintf("%s-%s-%s", n.tenantID, n.projectID, n.clusterID))
}

// GetUniqueNameByProjectID returns a unique name by projectID.
// the name is generated by md5(tenantID-projectID)
func (n *Namer) GetUniqueNameByProjectID() string {
	return MD5(fmt.Sprintf("%s-%s", n.tenantID, n.projectID))
}

func (n *Namer) GetUniqueNameByInput(input string) string {
	return MD5(input)
}

func NameLargerThan(a, b string) bool {
	return strings.Split(a, "-")[1] > strings.Split(b, "-")[1]
}

func MD5(s string) string {
	sum := md5.Sum([]byte(s))
	return hex.EncodeToString(sum[:])
}

func MD5Short(s string) string {
	return MD5(s)[:24]
}

func InceareName(name string) string {
	tmp := strings.Split(name, "-")
	num, err := strconv.Atoi(tmp[1])
	if err != nil {
		panic(err)
	}
	return tmp[0] + "-" + fmt.Sprintf("%d", num+1)
}

// GenTenantLabelKey exports the genTenantLabelKey func
var GenTenantLabelKey = genTenantLabelKey

func genTenantLabelKey(tenantID string) string {
	return fmt.Sprintf("%s%s", v1alpha1.TenantIDKeyPrefix, tenantID)
}

func GetIDsFromLabel(labels map[string]string, prefix string) []string {
	tenants := []string{}
	for key, value := range labels {
		if strings.HasPrefix(key, prefix) && value == "true" {
			tenants = append(tenants, strings.TrimPrefix(key, prefix))
		}
	}
	return tenants
}

// GenProjectLabelKey exports the genProjectLabelKey func
var GenProjectLabelKey = genProjectLabelKey

func genProjectLabelKey(projectID string) string {
	return fmt.Sprintf("%s%s", v1alpha1.ProjectIDKeyPrefix, projectID)
}

func GenTaskFirstPastAnnotationKey(taskName string) string {
	return fmt.Sprintf("%s%s", v1alpha1.TaskFirstPassTimeAnnotationKeyPrefix, taskName)
}

var GenClusterLabelKey = genClusterLabelKey

func genClusterLabelKey(clusterID string) string {
	return fmt.Sprintf("%s%s", v1alpha1.ClusterIDKeyPrefix, clusterID)
}

func GetRelatedTenantProjects(labels map[string]string) (tenants []string, projects []string) {
	for key, value := range labels {
		if strings.HasPrefix(key, v1alpha1.TenantIDKeyPrefix) && value == "true" {
			tenants = append(tenants, strings.TrimPrefix(key, v1alpha1.TenantIDKeyPrefix))
		}
		if strings.HasPrefix(key, v1alpha1.ProjectIDKeyPrefix) && value == "true" {
			projects = append(projects, strings.TrimPrefix(key, v1alpha1.ProjectIDKeyPrefix))
		}
	}
	return
}

func GenAWSRoleArn(account, rolename string) string {
	return fmt.Sprintf("arn:aws:iam::%s:role/%s", account, rolename)
}
