package vector_agent

import (
	"bytes"
	"context"
	"text/template"

	"github.com/pingcap/errors"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

// TODO(zhongzc): Once the content of the configuration is changed, an apply mechanism
//
//	should be added to restart cluster agents, e.g. a new annotation
//	`checksum/config` in spec.template.metadata of the deployment, which
//	is missing now.
const configTemplate = `data_dir = "{{ .DataPath }}"

[api]
enabled = true

[sources.topsql]
type = "topsql"
pd_address = "db-pd:2379"
tls.ca_path = "{{ .TLSPath }}/secret_${K8S_NAMESPACE}_db-cluster-client-secret_ca.crt"
tls.crt_path = "{{ .TLSPath }}/secret_${K8S_NAMESPACE}_db-cluster-client-secret_tls.crt"
tls.key_path = "{{ .TLSPath }}/secret_${K8S_NAMESPACE}_db-cluster-client-secret_tls.key"

[transforms.add_meta]
type = "remap"
inputs = [ "topsql" ]
source = """
.labels.provider = "${PROVIDER}"
.labels.region = "${REGION}"
.labels.k8s_cluster_name = "${K8S_CLUSTER_NAME}"
.labels.k8s_namespace = "${K8S_NAMESPACE}"
.labels.project_id = "${PROJECT_ID}"
.labels.tenant_id = "${TENANT_ID}"
.labels.cluster_id = "${CLUSTER_ID}"
"""

[sinks.vm]
type = "vm_import"
inputs = [ "add_meta" ]
endpoint = "{{ .VMImportURL }}/insert/${CLUSTER_ID}/prometheus/api/v1/import"
batch.max_events = 1000
batch.max_bytes = 1048576 # 1MiB
batch.timeout_secs = 1
buffer.type = "disk"
buffer.max_size = 1073741824 # 1GiB
buffer.when_full = "drop_newest"
`

var (
	tmpl, _ = template.New("cluster_vector_config").Parse(configTemplate)
)

// EnvLabels are labels required to present as environment variables.
type EnvLabels struct {
	// K8sClusterName is like `shoot--nightly--10cfb004`.
	K8sClusterName string
	// K8sNamespace is like `tidb123456`.
	K8sNamespace string

	Provider string
	Region   string

	ProjectID string
	TenantID  string
	ClusterID string
}

const (
	configDir    = "/etc/vector"
	dataDir      = "/vector-data-dir"
	tlsMountPath = "/var/lib/cluster-assets-tls"
)

type ConfigArgs struct {
	DataPath    string
	TLSPath     string
	VMImportURL string
}

func CreateConfigMap(ctx context.Context, shootClient client.Client, name, namespace, vmImportURL string) error {
	configArgs := &ConfigArgs{
		DataPath:    dataDir,
		TLSPath:     tlsMountPath,
		VMImportURL: vmImportURL,
	}

	configContent, err := BuildConfigContent(configArgs)
	if err != nil {
		return errors.Annotate(err, "failed to generate vector config")
	}

	configMap := &corev1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      name,
			Namespace: namespace,
		},
	}

	if _, err = controllerutil.CreateOrUpdate(ctx, shootClient, configMap, func() error {
		if configMap.Data == nil {
			configMap.Data = make(map[string]string)
		}
		configMap.Data["vector.toml"] = configContent
		return nil
	}); err != nil {
		return errors.Annotate(err, "failed to create or update vector configmap")
	}
	return nil
}

func BuildConfigContent(args *ConfigArgs) (string, error) {
	var res bytes.Buffer
	if err := tmpl.Execute(&res, args); err != nil {
		return "", err
	}

	return res.String(), nil
}
