package maker

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"

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

type ElasticOpt func(*elasticOpt)

type elasticOpt struct {
	MakeHelper bool
	MemRate    int
	Storage    string
}

func WithElasticMakeHelper(makeHelper bool) ElasticOpt {
	return func(o *elasticOpt) {
		o.MakeHelper = makeHelper
	}
}

func WithElasticMemRate(memRate int) ElasticOpt {
	return func(o *elasticOpt) {
		if memRate > 0 {
			o.MemRate = memRate
		}
	}
}

func WithElasticStorageGi(storage string) ElasticOpt {
	return func(o *elasticOpt) {
		if matched, _ := regexp.MatchString(`^\d+(\.\d+)?[EPTGMK]i?$`, storage); matched {
			o.Storage = storage
		}
	}
}

func (m *maker) Elastic(ctx context.Context, opts ...ElasticOpt) error {
	const (
		dockerFile = `
FROM docker-mirror.yizhisec.com/library/alpine:3.22.2

WORKDIR /data

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories && apk add curl

ENV TZ=Asia/Shanghai

COPY plugins /data/plugins
COPY create_index.sh /data/create_index.sh
RUN chmod +x /data/create_index.sh
`
		helperImageName = "hub.yizhisec.com/hybridscope/v2/es-init-helper:alpine-3.22.2"
		pluginUrl       = "https://artifactory.yizhisec.com:443/artifactory/filestore/hsv3/dependency/elasticsearch/v2-es-plugins.tar.gz"
	)

	var (
		err               error
		output            []byte
		location          = filepath.Join(opt.Cfg.Make.Dir, "dependency", "elastic")
		helperTarLocation = filepath.Join(opt.Cfg.Make.Dir, "dependency", "image", "es-init-helper.alpine-3.22.2.tar")
	)

	opt := &elasticOpt{
		MemRate: 1,
		Storage: "100Gi",
	}
	for _, fn := range opts {
		fn(opt)
	}

	logger.Info("☑️ maker.Elastic: 开始构建 elasticsearch(es) 依赖...")
	logger.Debug("☑️ maker.Elastic: 开始构建 elasticsearch(es) 依赖..., opt = %#v", opt)

	logger.Debug("☑️ maker.Elastic: 创建目录 %s", location)
	if err = os.MkdirAll(location, 0755); err != nil {
		logger.Debug("❌ maker.Elastic: 创建目录失败: %v", err)
		return err
	}
	logger.Debug("✅ maker.Elastic: 创建目录 %s 成功", location)

	if opt.MakeHelper {
		tmp := filepath.Join(os.TempDir(), "make-es")

		logger.Debug("☑️ maker.Elastic: 构建 helper..., dir = %s", tmp)

		logger.Debug("☑️ maker.Elastic: 删除并创建临时目录 %s", tmp)
		if err = os.RemoveAll(tmp); err != nil {
			logger.Debug("❌ maker.Elastic: 删除临时目录失败: %v", err)
			return err
		}

		if err = os.MkdirAll(tmp, 0755); err != nil {
			logger.Debug("❌ maker.Elastic: 创建临时目录失败: %v", err)
			return err
		}
		logger.Debug("✅ maker.Elastic: 删除并创建临时目录 %s 成功", tmp)

		logger.Debug("☑️ maker.Elastic: 写入 Dockerfile ...")
		if err = os.WriteFile(filepath.Join(tmp, "Dockerfile"), []byte(dockerFile), 0644); err != nil {
			logger.Debug("❌ maker.Elastic: 写入 Dockerfile 失败: %v", err)
			return err
		}
		logger.Debug("✅ maker.Elastic: 写入 Dockerfile 成功")

		logger.Debug("☑️ maker.Elastic: 下载 es 插件... url = %s", pluginUrl)
		if err = archiver.DownloadAndExtract(
			ctx,
			pluginUrl,
			tmp,
			archiver.WithInsecureSkipVerify(),
		); err != nil {
			logger.Debug("❌ maker.Elastic: 下载 es 插件失败: url = %s, err = %v", pluginUrl, err)
			return err
		}
		logger.Debug("✅ maker.Elastic: 下载 es 插件成功, url = %s", pluginUrl)

		logger.Debug("☑️ maker.Elastic: 写入 create_index.sh 文件...")
		if err = os.WriteFile(filepath.Join(tmp, "create_index.sh"), resource.BashESInit, 0644); err != nil {
			logger.Debug("❌ maker.Elastic: 写入 create_index.sh 文件失败: %v", err)
			return err
		}
		logger.Debug("✅ maker.Elastic: 写入 create_index.sh 文件成功")

		helpCmd := exec.CommandContext(ctx, "docker", "build", "-t",
			helperImageName,
			"-f", filepath.Join(tmp, "Dockerfile"),
			tmp,
		)

		logger.Debug("☑️ maker.Elastic: 重新构建 helper 镜像..., cmd = %s", helpCmd.String())
		if output, err = helpCmd.CombinedOutput(); err != nil {
			logger.Debug("MakeES: 重新构建 helper 镜像失败, err = %v, output = %s", err, string(output))
			return err
		}
		logger.Debug("✅ maker.Elastic: 重新构建 helper 镜像成功, cmd = %s", helpCmd.String())

		logger.Debug("✅ maker.Elastic: 构建 helper 成功, dir = %s", tmp)
	}

	logger.Debug("☑️ maker.Elastic: 准备 es init helper 镜像..., location = %s", helperTarLocation)
	if err = m.Image(
		ctx,
		helperImageName,
		WithImageSave(helperTarLocation),
	); err != nil {
		logger.Debug("❌ maker.Elastic: 准备 es init helper 镜像失败, location = %s, err = %v", helperTarLocation, err)
		return err
	}
	logger.Debug("✅ maker.Elastic: 准备 es init helper 镜像成功, location = %s", helperTarLocation)

	bs := []byte(fmt.Sprintf(resource.YAMLES,
		opt.MemRate, opt.MemRate*2,
		opt.MemRate, opt.MemRate,
		opt.MemRate*2, opt.MemRate*2,
		opt.Storage,
	))

	logger.Debug("☑️ maker.Elastic: 写入 es.yaml 文件...")
	if err = os.WriteFile(filepath.Join(location, "es.yaml"), bs, 0644); err != nil {
		logger.Debug("❌ maker.Elastic: 写入 es.yaml 文件失败: %v", err)
		return err
	}
	logger.Debug("✅ maker.Elastic: 写入 es.yaml 文件成功")

	logger.Debug("☑️ maker.Elastic: 写入 kibana.yaml 文件...")
	if err = os.WriteFile(filepath.Join(location, "kibana.yaml"), resource.YAMLKibana, 0644); err != nil {
		logger.Debug("❌ maker.Elastic: 写入 kibana.yaml 文件失败: %v", err)
		return err
	}
	logger.Debug("✅ maker.Elastic: 写入 kibana.yaml 文件成功")

	logger.Info("✅ maker.Elastic: 构建 elastic(es) 依赖成功!!!")
	return nil
}
