//nolint:mnd // it's a test file
package testutils

import (
	rm "github.com/tidbcloud/aws-shared-provider/pkg/tidbworker/resourcemanager/types"
	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"sigs.k8s.io/yaml"
)

type ClusterConfig struct {
	Namespace    string
	SecretName   string
	WorkerConfig WorkerConfig
	PoolsConfig  PoolsConfig
}

type WorkerConfig struct {
	Name          string
	TiDBImage     string
	TiDBConfig    string
	StartupScript string
	SemConfig     string
}

type PoolsConfig struct {
	Name  string
	Pools map[rm.WorkerPool]*PoolConfig
}

type PoolConfig struct {
	Size      int                     `yaml:"size"`
	Resources v1.ResourceRequirements `yaml:"resources"`
}

func (c *ClusterConfig) Clone() *ClusterConfig {
	if c == nil {
		return nil
	}
	return &ClusterConfig{
		Namespace:    c.Namespace,
		SecretName:   c.SecretName,
		WorkerConfig: c.WorkerConfig,
		PoolsConfig:  c.PoolsConfig.Clone(),
	}
}

func (c PoolsConfig) Clone() PoolsConfig {
	cloned := PoolsConfig{
		Name:  c.Name,
		Pools: make(map[rm.WorkerPool]*PoolConfig, len(c.Pools)),
	}
	for pool, cfg := range c.Pools {
		cloned.Pools[pool] = cfg.Clone()
	}
	return cloned
}

func (c *PoolConfig) Clone() *PoolConfig {
	if c == nil {
		return nil
	}
	return &PoolConfig{
		Size:      c.Size,
		Resources: *c.Resources.DeepCopy(),
	}
}

func DefaultConfig() *ClusterConfig {
	return &ClusterConfig{
		Namespace:  "tidb-worker",
		SecretName: "",
		WorkerConfig: WorkerConfig{
			Name:          "worker-config",
			TiDBImage:     "fake-time-image:v1.2.3",
			TiDBConfig:    "test config",
			StartupScript: "sleep infinity",
			SemConfig:     "{}",
		},
		PoolsConfig: PoolsConfig{
			Name: "pools-config",
			Pools: map[rm.WorkerPool]*PoolConfig{
				"worker-100m-128Mi": {
					Size: 3,
					Resources: v1.ResourceRequirements{
						Requests: v1.ResourceList{
							v1.ResourceCPU:    resource.MustParse("100m"),
							v1.ResourceMemory: resource.MustParse("128Mi"),
						},
						Limits: v1.ResourceList{
							v1.ResourceCPU:    resource.MustParse("2"),
							v1.ResourceMemory: resource.MustParse("2Gi"),
						},
					},
				},
				"worker-100m-512Mi": {
					Size: 2,
					Resources: v1.ResourceRequirements{
						Requests: v1.ResourceList{
							v1.ResourceCPU:    resource.MustParse("100m"),
							v1.ResourceMemory: resource.MustParse("512Mi"),
						},
						Limits: v1.ResourceList{
							v1.ResourceCPU:    resource.MustParse("2"),
							v1.ResourceMemory: resource.MustParse("2Gi"),
						},
					},
				},
			},
		},
	}
}

func parseWorkerConfig(cfg *ClusterConfig) *v1.ConfigMap {
	return &v1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      cfg.WorkerConfig.Name,
			Namespace: cfg.Namespace,
		},
		Data: map[string]string{
			"tidb-image":     cfg.WorkerConfig.TiDBImage,
			"tidb-config":    cfg.WorkerConfig.TiDBConfig,
			"startup-script": cfg.WorkerConfig.StartupScript,
			"sem-config":     cfg.WorkerConfig.SemConfig,
		},
	}
}

func parsePoolsConfig(cfg *ClusterConfig) (*v1.ConfigMap, error) {
	poolsData, err := yaml.Marshal(cfg.PoolsConfig.Pools)
	if err != nil {
		return nil, err
	}
	return &v1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      cfg.PoolsConfig.Name,
			Namespace: cfg.Namespace,
		},
		Data: map[string]string{
			"pools": string(poolsData),
		},
	}, nil
}
