package task

import (
	"bytes"
	"context"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"strconv"
	"strings"

	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"

	"github.com/tidbcloud/observability/agent-control-server/pkg/config"
)

const (
	serverlessVectorName    = "o11y-vector-sharedpool"
	serverlessTLSSecretName = "o11y-vector-sharedpool-tidb-tls"

	serverlessVectorDefaultPDAddress = "serverless-cluster-pd.tidb-serverless.svc:2379"
	serverlessVectorDefaultSecret    = "vector-cluster-secret"
	serverlessVectorDefaultMgrAddr   = "https://manager-server.tidb-admin.svc:8000"
	serverlessVectorDefaultNamespace = "super-vip-tidb-pool,canary-super-vip-tidb-pool"
)

func (t *VectorTask) buildServerlessExtValues(ctx context.Context, cli client.Client, cfg *config.VectorConfig) (map[string]string, error) {
	values := map[string]string{
		"PDAddress":        ensureHTTPSAddress(serverlessVectorDefaultPDAddress),
		"ManagerServerURL": serverlessVectorDefaultMgrAddr,
		"TiDBNamespace":    serverlessVectorDefaultNamespace,
		"EnableTiKVTopSQL": strconv.FormatBool(cfg.EnableTiKVTopSQL),
	}
	if cfg.PDAddress != "" {
		values["PDAddress"] = ensureHTTPSAddress(cfg.PDAddress)
	}
	if cfg.ManagerServerURL != "" {
		values["ManagerServerURL"] = ensureHTTPSAddress(cfg.ManagerServerURL)
	}
	if cfg.TiDBNamespace != "" {
		values["TiDBNamespace"] = cfg.TiDBNamespace
	}

	clusterSecretName := serverlessVectorDefaultSecret
	if cfg.ClusterSecretName != "" {
		clusterSecretName = cfg.ClusterSecretName
	}
	tlsSecretName, err := t.ensureServerlessTLSSecret(ctx, cli, clusterSecretName)
	if err != nil {
		return nil, err
	}
	values["TLSSecretName"] = tlsSecretName

	var replicas uint32 = 1
	if cfg.Replicas > 0 {
		replicas = cfg.Replicas
	}
	values["Replicas"] = fmt.Sprintf("%d", replicas)
	return values, nil
}

func (t *VectorTask) ensureServerlessTLSSecret(ctx context.Context, cli client.Client, clusterSecretName string) (string, error) {
	namespace := t.buildNamespace()
	sourceSecret := &corev1.Secret{}
	if err := cli.Get(ctx, client.ObjectKey{
		Name:      clusterSecretName,
		Namespace: namespace,
	}, sourceSecret); err != nil {
		return "", fmt.Errorf("failed to get serverless vector tls secret %s/%s: %w", namespace, clusterSecretName, err)
	}

	targetSecret, err := t.buildServerlessTLSSecret(sourceSecret)
	if err != nil {
		return "", err
	}

	currentSecret := &corev1.Secret{
		ObjectMeta: metav1.ObjectMeta{
			Name:      targetSecret.Name,
			Namespace: targetSecret.Namespace,
		},
	}
	_, err = controllerutil.CreateOrUpdate(ctx, cli, currentSecret, func() error {
		currentSecret.Type = targetSecret.Type
		currentSecret.Data = targetSecret.Data
		currentSecret.Labels = targetSecret.Labels
		currentSecret.Annotations = targetSecret.Annotations
		return nil
	})
	if err != nil {
		return "", fmt.Errorf("failed to create or update serverless vector tls secret %s/%s: %w", targetSecret.Namespace, targetSecret.Name, err)
	}

	return targetSecret.Name, nil
}

func (t *VectorTask) buildServerlessTLSSecret(sourceSecret *corev1.Secret) (*corev1.Secret, error) {
	namespaceName := fmt.Sprintf("%s/%s", sourceSecret.Namespace, sourceSecret.Name)
	caCRT, ok := sourceSecret.Data["ca.crt"]
	if !ok {
		return nil, fmt.Errorf("serverless vector tls secret %s misses key ca.crt", namespaceName)
	}
	tlsCRT, ok := sourceSecret.Data[corev1.TLSCertKey]
	if !ok {
		return nil, fmt.Errorf("serverless vector tls secret %s misses key %s", namespaceName, corev1.TLSCertKey)
	}
	tlsKey, ok := sourceSecret.Data[corev1.TLSPrivateKeyKey]
	if !ok {
		return nil, fmt.Errorf("serverless vector tls secret %s misses key %s", namespaceName, corev1.TLSPrivateKeyKey)
	}

	normalizedTLSKey, err := normalizePrivateKeyToPKCS8(bytes.Clone(tlsKey))
	if err != nil {
		return nil, fmt.Errorf("failed to normalize serverless vector tls secret %s private key to PKCS#8: %w", namespaceName, err)
	}
	return &corev1.Secret{
		ObjectMeta: metav1.ObjectMeta{
			Name:      serverlessTLSSecretName,
			Namespace: t.buildNamespace(),
		},
		Type: corev1.SecretTypeTLS,
		Data: map[string][]byte{
			"ca.crt":                bytes.Clone(caCRT),
			corev1.TLSCertKey:       bytes.Clone(tlsCRT),
			corev1.TLSPrivateKeyKey: normalizedTLSKey,
		},
	}, nil
}

func (t *VectorTask) deleteServerlessTLSSecret(ctx context.Context, cli client.Client) error {
	namespace := t.buildNamespace()
	secret := &corev1.Secret{
		ObjectMeta: metav1.ObjectMeta{
			Name:      serverlessTLSSecretName,
			Namespace: namespace,
		},
	}
	if err := cli.Delete(ctx, secret); err != nil && client.IgnoreNotFound(err) != nil {
		return fmt.Errorf("failed to delete serverless vector tls secret %s/%s: %w", secret.Namespace, secret.Name, err)
	}
	return nil
}

func ensureHTTPSAddress(addr string) string {
	if strings.Contains(addr, "://") {
		return addr
	}
	return "https://" + addr
}

func normalizePrivateKeyToPKCS8(privateKeyPEM []byte) ([]byte, error) {
	block, _ := pem.Decode(privateKeyPEM)
	if block == nil {
		return nil, fmt.Errorf("failed to decode private key PEM")
	}

	switch block.Type {
	case "PRIVATE KEY":
		if _, err := x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
			return nil, fmt.Errorf("failed to parse PKCS#8 private key: %w", err)
		}
		return append([]byte(nil), privateKeyPEM...), nil
	case "RSA PRIVATE KEY":
		privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
		if err != nil {
			return nil, fmt.Errorf("failed to parse PKCS#1 RSA private key: %w", err)
		}
		pkcs8Bytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
		if err != nil {
			return nil, fmt.Errorf("failed to marshal PKCS#8 private key: %w", err)
		}
		return pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: pkcs8Bytes}), nil
	default:
		return nil, fmt.Errorf("unsupported private key PEM type %q", block.Type)
	}
}
