package metric_agent

import (
	"gopkg.in/yaml.v2"

	"github.com/tidbcloud/infra-api/pkg/o11y/prom_config"
)

const (
	tidbTlsVolumeName = "tls-assets"
	// The ClusterCriticalPriorityClassName ensures that
	// when a node triggers an eviction due to memory pressure,
	// the agent pod is the last one evicted if multiple pod memory usage exceeds the request.
	// Refer to:
	// - https://kubernetes.io/docs/tasks/administer-cluster/guaranteed-scheduling-critical-addon-pods/
	// - https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/
	ClusterCriticalPriorityClassName = "tidb-cluster-o11y-critical"
)

func BuildDefaultVmagentChartValuesForTidbCluster(imageRepo, imageTag, storageClass string, promConfig *prom_config.PromConfig, replicaCount int64, remoteWriteUrls ...string) ([]byte, error) {
	if promConfig == nil {
		promConfig = &prom_config.PromConfig{}
	}
	values := ChartValues{
		ReplicaCount: replicaCount,
		Deployment: Deployment{
			Enabled: true,
			// Metric Agent deployment pod use one pvc and share state file between multiple replicaset. The agent process also lock the state file to prevent other agent to process concurrently.
			// If we use rollingupdate strategy, the newer agent will never be ready because the old one won't release the file lock.
			Strategy: map[string]interface{}{
				"type": "Recreate",
			},
		},
		Statefulset: Statefulset{
			Enabled: false,
		},
		RemoteWriteUrls: remoteWriteUrls,
		ExtraArgs: map[string]string{
			"envflag.enable":                                 "true",
			"envflag.prefix":                                 "VM_",
			"loggerFormat":                                   "json",
			"remoteWrite.maxDiskUsagePerURL":                 "2000MiB",
			"remoteWrite.queues":                             "1",
			"promscrape.config.strictParse":                  "false",
			"promscrape.suppressDuplicateScrapeTargetErrors": "true",
		},
		ExtraVolumes: []ExtraVolume{
			{
				Name: tidbTlsVolumeName,
				Secret: Secret{
					SecretName:  "tidbmonitor-db-tls-assets",
					DefaultMode: 420,
				},
			},
		},
		ExtraVolumeMounts: []ExtraVolumeMount{
			{
				Name:      tidbTlsVolumeName,
				MountPath: "/var/lib/cluster-assets-tls",
				ReadOnly:  true,
			},
		},
		Resources: Resources{
			Requests: &Resource{
				Memory: "250Mi",
			},
			Limits: &Resource{
				Memory: "1000Mi",
			},
		},
		Persistence: Persistence{
			Enabled:          true,
			StorageClassName: storageClass,
			AccessModes:      []string{"ReadWriteOnce"},
			Size:             "2Gi",
		},
		Config: *promConfig,
		Image: Image{
			Repository: imageRepo,
			Tag:        imageTag,
		},
		PriorityClassName: ClusterCriticalPriorityClassName,
	}
	return yaml.Marshal(values)
}

type ChartValues struct {
	ReplicaCount      int64                  `yaml:"replicaCount"`
	Deployment        Deployment             `yaml:"deployment"`
	Statefulset       Statefulset            `yaml:"statefulset"`
	RemoteWriteUrls   []string               `yaml:"remoteWriteUrls"`
	ExtraArgs         map[string]string      `yaml:"extraArgs"`
	ExtraLabels       map[string]string      `yaml:"extraLabels"`
	ExtraVolumes      []ExtraVolume          `yaml:"extraVolumes"`
	ExtraVolumeMounts []ExtraVolumeMount     `yaml:"extraVolumeMounts"`
	Resources         Resources              `yaml:"resources"`
	Persistence       Persistence            `yaml:"persistence"`
	Config            prom_config.PromConfig `yaml:"config"`
	Image             Image                  `yaml:"image"`
	Affinity          map[string]interface{} `yaml:"affinity"`
	PriorityClassName string                 `yaml:"priorityClassName"`
}

type Deployment struct {
	Enabled  bool                   `yaml:"enabled"`
	Strategy map[string]interface{} `yaml:"strategy"`
}

type Statefulset struct {
	Enabled bool `yaml:"enabled"`
}

type ExtraVolumeMount struct {
	Name      string `yaml:"name"`
	ReadOnly  bool   `yaml:"readOnly"`
	MountPath string `yaml:"mountPath"`
}

type ExtraVolume struct {
	Name   string `yaml:"name"`
	Secret Secret `yaml:"secret"`
}

type Secret struct {
	SecretName  string `yaml:"secretName"`
	DefaultMode int64  `yaml:"defaultMode"`
}

type Persistence struct {
	Enabled          bool     `yaml:"enabled"`
	StorageClassName string   `yaml:"storageClassName"`
	AccessModes      []string `yaml:"accessModes"`
	Size             string   `yaml:"size"`
}

type Resources struct {
	Limits   *Resource `yaml:"limits,omitempty"`
	Requests *Resource `yaml:"requests,omitempty"`
}

type Resource struct {
	CPU    string `yaml:"cpu,omitempty"`
	Memory string `yaml:"memory,omitempty"`
}

type Image struct {
	Repository string `yaml:"repository"`
	Tag        string `yaml:"tag"`
}
