package maker

import (
	"context"
	"encoding/base64"
	"fmt"
	"os"
	"path/filepath"
	"regexp"

	"gitea.loveuer.com/yizhisec/pkg3/logger"
	"yizhisec.com/hsv2/forge/internal/opt"
	"yizhisec.com/hsv2/forge/pkg/downloader"
)

type MysqlOpt func(*mysqlOpt)

type mysqlOpt struct {
	Replica  int
	Storage  string
	Password string
}

func WithMySQLReplica(replica int) MysqlOpt {
	return func(o *mysqlOpt) {
		o.Replica = replica
	}
}

func WithMySQLStorage(storage string) MysqlOpt {
	return func(o *mysqlOpt) {
		// validate Kubernetes storage size string (e.g., "50Gi", "100Mi")
		if matched, _ := regexp.MatchString(`^\d+(\.\d+)?[EPTGMK]i?$`, storage); matched {
			o.Storage = storage
		}
	}
}

func WithMySQLPassword(password string) MysqlOpt {
	return func(o *mysqlOpt) {
		if password != "" {
			o.Password = password
		}
	}
}

func (m *maker) MySQL(ctx context.Context, opts ...MysqlOpt) error {
	const (
		_yaml = `
apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
  namespace: db-mysql
type: Opaque
data:
  ROOT_PASSWORD: %s
---

apiVersion: mysql.presslabs.org/v1alpha1
kind: MysqlCluster
metadata:
  name: mysql-cluster
  namespace: db-mysql
spec:
  mysqlVersion: "8.0"
  replicas: %d
  image: docker.io/library/percona:8.0.28-20
  secretName: mysql-secret
  volumeSpec:
    persistentVolumeClaim:
      accessModes: ["ReadWriteOnce"]
      storageClassName: longhorn
      resources:
        requests:
          storage: %s
    podSpec:
      resources:
        requests:
          cpu: "250m"
          memory: "250Mi"
        limits:
          cpu: "2"
          memory: "4Gi"
#     affinity:
#       podAntiAffinity:
#         requiredDuringSchedulingIgnoredDuringExecution:  # 强制规则
#           - labelSelector:
#               matchExpressions:
#                 - key: app.kubernetes.io/name
#                   operator: In
#                   values: ["mysql"]
#                 - key: app.kubernetes.io/instance
#                   operator: In
#                   values: ["mysql-cluster"]
#             topologyKey: "kubernetes.io/hostname"  # 确保不同节点
---

apiVersion: mysql.presslabs.org/v1alpha1
kind: MysqlDatabase
metadata:
  name: my-database-mie
  namespace: db-mysql
spec:
  database: mie
  clusterRef:
    name: mysql-cluster
    namespace: db-mysql
`
	)

	var (
		o = &mysqlOpt{
			Replica:  2,
			Storage:  "50Gi",
			Password: "L0hMysql.",
		}

		err         error
		chartURL    = "https://artifactory.yizhisec.com:443/artifactory/filestore/hsv3/charts/mysql-operator-0.6.3.tgz"
		mysqlDir    = filepath.Join(opt.Cfg.Make.Dir, "dependency", "mysql")
		chartFile   = filepath.Join(mysqlDir, "mysql-operator-0.6.3.tgz")
		clusterFile = filepath.Join(mysqlDir, "cluster.yaml")
	)

	for _, fn := range opts {
		fn(o)
	}

	logger.Info("☑️ 开始构建 MySQL 资源...")

	if err = os.MkdirAll(mysqlDir, 0755); err != nil {
		return err
	}

	o.Password = base64.StdEncoding.EncodeToString([]byte(o.Password))

	logger.Debug("正在下载 MySQL operator chart..., url = %s, dir = %s", chartURL, mysqlDir)
	if err = downloader.Download(
		ctx,
		chartURL,
		chartFile,
		downloader.WithInsecureSkipVerify(),
	); err != nil {
		logger.Info("❌ 下载 MySQL operator chart 失败")
		return err
	}
	logger.Debug("✅ 成功下载 MySQL operator chart")

	bs := []byte(fmt.Sprintf(_yaml, o.Password, o.Replica, o.Storage))

	// Generate secret.yaml
	if err = os.WriteFile(clusterFile, bs, 0644); err != nil {
		logger.Debug("创建 database.yaml 失败: %v", err)
		logger.Info("❌ 创建 database.yaml 失败")
		return err
	}

	logger.Debug("✅ 成功创建 database.yaml")

	logger.Info("✅ MySQL 资源构建成功!!!")

	return nil
}
