package maker

import (
	"context"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"gitea.loveuer.com/yizhisec/pkg3/logger"
	"github.com/samber/lo"
	"yizhisec.com/hsv2/forge/internal/opt"
	"yizhisec.com/hsv2/forge/pkg/downloader"
	"yizhisec.com/hsv2/forge/pkg/extractor"
	"yizhisec.com/hsv2/forge/pkg/tool/random"
)

type ConfigMapOpt func(*configMapOpt)
type configMapOpt struct {
	Vendor string
}

func (m *maker) ConfigMap(ctx context.Context, opts ...ConfigMapOpt) error {

	const (
		sslPubCrt = `-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4QohTyK0GGjPW20T/B+K
GDfSPPCbHoy7Dpzk7NHtVgHWLds21+SRN5EN0p/6HLc5XrMGmn1eW6uMBHHn6hBX
JVuwJ4j9+mjoXqA+IwzQYI8GdFR4uge/UyAe5D2Vlo7p5bjfdSq1ZIHRiOmpct59
GEXTtGR709gnxuP4yd9kNswwfCcanTY8N5ZS+m9jSkIOVKKShJ02Y8OaIaspvkgo
qiH7P/rwYrcB53WkvrM1+ktmHm65yJsDUxPfRgkcfo6X+2dtMQuM6leTmRHwRmnL
bwP+UE6H3cvC0hgttJApacZe2ewhZDqfR4lnBlP1zHwCTc8wjpDXnFIWIHuGnFWy
ip/24LB7noaq2r2rfr/pLX5ONcb5swAWoESQ87zQCjJSy5gxRUB0ZwyeNsVGaYKt
qyUaev1AGN4Gs5PO52QXCOOudp7R0QlJkt/UZe1e057nasrS28PJALboHuP5mpjQ
s2NL1GuOeYhwX5khvW3ghB3x7+z9Lexnd30JAywOz9y3YctQMkS6iD3D+YHNJfIu
5VLYDPKbvRnfgwzdsv5kvKy1VZZEVdWGMqLlKDTFSPZdiQ1lGk5wYKZPXKQ3DI8q
ul5FJ0pkrW3VMewOysX2Hjoakftvajpuf+Mtkz3C2vDRAsBBTXhKDJZhCGAkibVI
YxyddOvOMDfCI3Xx2VjicukCAwEAAQ==
-----END PUBLIC KEY-----`
		sslWebCrt = `-----BEGIN CERTIFICATE-----
MIIBeTCCASACAQEwCgYIKoZIzj0EAwIwTTELMAkGA1UEBhMCQ04xEjAQBgNVBAgM
CUd1YW5nZG9uZzESMBAGA1UEBwwJR3Vhbmd6aG91MRYwFAYDVQQKDA1ZaVpoaSBS
b290IENBMB4XDTIyMDgyMTA4MjEzMloXDTMyMDgxODA4MjEzMlowRTELMAkGA1UE
BhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzESMBAGA1UEBwwJR3Vhbmd6aG91MQ4w
DAYDVQQKDAVZaVpoaTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOI4Fy+rT8ca
AuW390kWqhfqtv1a9+KISsESg/tuUiNYile3Tl7ndMzZmBJDlIOGXt8KcFc8t7kU
Lx/nUF3g4rcwCgYIKoZIzj0EAwIDRwAwRAIgFc6wgYlcdUoFtfZDEeW8a2xloUA3
HaPnkqCPZlKzwlACIARWSaWA64UTC+et/n3LZY9ZGWRatzxhhALToM33pewH
-----END CERTIFICATE-----`
		sslClientCrt = `-----BEGIN CERTIFICATE-----
MIIBezCCASACAQEwCgYIKoZIzj0EAwIwTTELMAkGA1UEBhMCQ04xEjAQBgNVBAgM
CUd1YW5nZG9uZzESMBAGA1UEBwwJR3Vhbmd6aG91MRYwFAYDVQQKDA1ZaVpoaSBS
b290IENBMB4XDTIyMTIwMjEwMTMxNloXDTMyMTEyOTEwMTMxNlowRTELMAkGA1UE
BhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzESMBAGA1UEBwwJR3Vhbmd6aG91MQ4w
DAYDVQQKDAVZaVpoaTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJ74lcE1h9K3
6ks6PPI9TrafVySsozy/2S4HTH05hfKSMTWUGjhrPLGexy5R3YzSk9eLNpfzEHEG
2VhrCDR3wNUwCgYIKoZIzj0EAwIDSQAwRgIhAK1pvrP4uOYbZt92IPuoQXK2ESYf
w0QG+/cJlho3pj3oAiEAnGhFUlFwMhV3LIjkE9SIY4zDlJeFORC9v/BjL1m1u6U=
-----END CERTIFICATE-----`
		sslClientKey = `-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIESZAIwzWT3R+6anwL8EI7l7va3LJlYCPMHWFTaSrH8OoAoGCCqGSM49
AwEHoUQDQgAEnviVwTWH0rfqSzo88j1Otp9XJKyjPL/ZLgdMfTmF8pIxNZQaOGs8
sZ7HLlHdjNKT14s2l/MQcQbZWGsINHfA1Q==
-----END EC PRIVATE KEY-----`
		sslClientCaCrt = `-----BEGIN CERTIFICATE-----
MIIBiTCCATACCQCe3EeGhAHb+DAKBggqhkjOPQQDAjBNMQswCQYDVQQGEwJDTjES
MBAGA1UECAwJR3Vhbmdkb25nMRIwEAYDVQQHDAlHdWFuZ3pob3UxFjAUBgNVBAoM
DVlpWmhpIFJvb3QgQ0EwHhcNMjIwNzI2MDY1NzI1WhcNMzIwNzIzMDY1NzI1WjBN
MQswCQYDVQQGEwJDTjESMBAGA1UECAwJR3Vhbmdkb25nMRIwEAYDVQQHDAlHdWFu
Z3pob3UxFjAUBgNVBAoMDVlpWmhpIFJvb3QgQ0EwWTATBgcqhkjOPQIBBggqhkjO
PQMBBwNCAATg+MJSN3USPg0GF3Vrt3ci07teA7UuxxJePLXMZVKNIdZ5viH2j6cQ
S5hFhcOi48nUX/+titpKgnia1qKkHrPUMAoGCCqGSM49BAMCA0cAMEQCIA1tPS1s
qTolNOc84eyZcuc1qAAdSERKjyIW1l8yuTKDAiBWLOBKAolylbhu46yB3Z2xKdp1
9Mv7I02zYZhbkVhcCA==
-----END CERTIFICATE-----`
		sslClientCaKey = `-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIFDTepl14/ve7Ye4BsC7NS3ItVN74kgGvWDUyPKHmeKhoAoGCCqGSM49
AwEHoUQDQgAE4PjCUjd1Ej4NBhd1a7d3ItO7XgO1LscSXjy1zGVSjSHWeb4h9o+n
EEuYRYXDouPJ1F//rYraSoJ4mtaipB6z1A==
-----END EC PRIVATE KEY-----`
		upsert = `#!/bin/bash

kubectl create configmap config-token --namespace hsv2 --from-file=token=./token --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap config-license-init --namespace hsv2 --from-file=server_license_init.conf=./server_license_init.conf --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap config-oem-data --namespace hsv2 --from-file=data.json=./oem_data.json --dry-run=client -o yaml | kubectl apply -f -

kubectl create configmap ssl-pub-crt --namespace hsv2 --from-file=pub_key=./ssl_pub.crt --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap ssl-client-crt --namespace hsv2 --from-file=client.crt=./ssl_client.crt --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap ssl-client-key --namespace hsv2 --from-file=client.key=./ssl_client.key --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap ssl-client-ca-crt --namespace hsv2 --from-file=client.ca.crt=./ssl_client_ca.crt --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap ssl-client-ca-key --namespace hsv2 --from-file=client.ca.key=./ssl_client_ca.key --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap ssl-web-crt --namespace hsv2 --from-file=web.server.crt=./ssl_web.crt --dry-run=client -o yaml | kubectl apply -f -
`
	)

	var (
		err          error
		dir          = filepath.Join(opt.Cfg.Make.Dir, "configmap")
		vendorUrlMap = map[string]string{
			"standard": "https://artifactory.yizhisec.com/artifactory/yizhisec-release/oem/release/2.1.0-std/oem.tar.gz",
			"elink":    "https://artifactory.yizhisec.com/artifactory/yizhisec-release/oem/release/2.1.0-std/oem_csgElink.tar.gz",
			"noah":     "https://artifactory.yizhisec.com/artifactory/yizhisec-release/oem/release/2.1.0-std/oem_noah.tar.gz",
		}
		o = &configMapOpt{
			Vendor: "standard",
		}
	)

	logger.Info("☑️ maker.ConfigMap: 开始构建 ConfigMap...")

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

	if _, ok := vendorUrlMap[o.Vendor]; !ok {
		logger.Debug("❌ maker.ConfigMap: 不支持的 vendor: %s", o.Vendor)
		return fmt.Errorf("vendor %s 不支持, 请从下面选择: %v", o.Vendor, lo.MapToSlice(vendorUrlMap, func(key string, value string) string {
			return key
		}))
	}

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

	// download oem.tar.gz
	logger.Debug("☑️ maker.ConfigMap: 下载 oem.tar.gz 文件: %s", vendorUrlMap[o.Vendor])
	if err = downloader.Download(ctx, vendorUrlMap[o.Vendor], filepath.Join(dir, "oem.tar.gz")); err != nil {
		logger.Debug("❌ maker.ConfigMap: 下载 oem.tar.gz 文件: %s 失败, 错误: %v", vendorUrlMap[o.Vendor], err)
		return err
	}
	logger.Debug("✅ maker.ConfigMap: 下载 oem.tar.gz 文件: %s 成功", vendorUrlMap[o.Vendor])

	// extract oem.tar.gz
	logger.Debug("☑️ maker.ConfigMap: 解压 oem.tar.gz 文件: %s", filepath.Join(dir, "oem.tar.gz"))
	if err = extractor.Extract(ctx, filepath.Join(dir, "oem.tar.gz"), dir); err != nil {
		logger.Debug("❌ maker.ConfigMap: 解压 oem.tar.gz 文件: %s 失败, 错误: %v", filepath.Join(dir, "oem.tar.gz"), err)
		return err
	}
	logger.Debug("✅ maker.ConfigMap: 解压 oem.tar.gz 文件: %s 成功", filepath.Join(dir, "oem.tar.gz"))

	// mv oem/data.json ./oem_data.json
	if err = os.Rename(filepath.Join(dir, "oem", "data.json"), filepath.Join(dir, "oem_data.json")); err != nil {
		logger.Debug("❌ maker.ConfigMap: 移动 oem/data.json 文件: %s 失败, 错误: %v", filepath.Join(dir, "oem", "data.json"), err)
		return err
	}
	logger.Debug("✅ maker.ConfigMap: 移动 oem/data.json 文件: %s 成功", filepath.Join(dir, "oem_data.json"))

	// generate random token 8 length, lower case
	logger.Debug("☑️ maker.ConfigMap: 写入 token 文件: %s", filepath.Join(dir, "token"))
	token := strings.ToLower(random.RandomString(8))
	if err = os.WriteFile(filepath.Join(dir, "token"), []byte(token), 0644); err != nil {
		logger.Debug("❌ maker.ConfigMap: 写入 token 文件: %s 失败, 错误: %v", filepath.Join(dir, "token"), err)
		return err
	}
	logger.Debug("✅ maker.ConfigMap: 写入 token 文件: %s 成功", filepath.Join(dir, "token"))

	// todo: server_license_init.conf
	// example content: {"uuid": "5044e2c0-1b15-475d-a193-7ee5d9c7b3ac", "install_time": 1669976272}

	// todo: write crt, key down to file
	if err = os.WriteFile(filepath.Join(dir, "ssl_pub.crt"), []byte(sslPubCrt), 0644); err != nil {
		logger.Debug("❌ maker.ConfigMap: 写入 ssl_pub.crt 文件: %s 失败, 错误: %v", filepath.Join(dir, "ssl_pub.crt"), err)
		return err
	}
	logger.Debug("✅ maker.ConfigMap: 写入 ssl_pub.crt 文件: %s 成功", filepath.Join(dir, "ssl_pub.crt"))

	if err = os.WriteFile(filepath.Join(dir, "ssl_web.crt"), []byte(sslWebCrt), 0644); err != nil {
		logger.Debug("❌ maker.ConfigMap: 写入 ssl_web.crt 文件: %s 失败, 错误: %v", filepath.Join(dir, "ssl_web.crt"), err)
		return err
	}
	logger.Debug("✅ maker.ConfigMap: 写入 ssl_web.crt 文件: %s 成功", filepath.Join(dir, "ssl_web.crt"))

	if err = os.WriteFile(filepath.Join(dir, "ssl_client.crt"), []byte(sslClientCrt), 0644); err != nil {
		logger.Debug("❌ maker.ConfigMap: 写入 ssl_client.crt 文件: %s 失败, 错误: %v", filepath.Join(dir, "ssl_client.crt"), err)
		return err
	}
	logger.Debug("✅ maker.ConfigMap: 写入 ssl_client.crt 文件: %s 成功", filepath.Join(dir, "ssl_client.crt"))

	if err = os.WriteFile(filepath.Join(dir, "ssl_client.key"), []byte(sslClientKey), 0644); err != nil {
		logger.Debug("❌ maker.ConfigMap: 写入 ssl_client.key 文件: %s 失败, 错误: %v", filepath.Join(dir, "ssl_client.key"), err)
		return err
	}
	logger.Debug("✅ maker.ConfigMap: 写入 ssl_client.key 文件: %s 成功", filepath.Join(dir, "ssl_client.key"))

	if err = os.WriteFile(filepath.Join(dir, "ssl_client_ca.crt"), []byte(sslClientCaCrt), 0644); err != nil {
		logger.Debug("❌ maker.ConfigMap: 写入 ssl_client_ca.crt 文件: %s 失败, 错误: %v", filepath.Join(dir, "ssl_client_ca.crt"), err)
		return err
	}
	logger.Debug("✅ maker.ConfigMap: 写入 ssl_client_ca.crt 文件: %s 成功", filepath.Join(dir, "ssl_client_ca.crt"))

	if err = os.WriteFile(filepath.Join(dir, "ssl_client_ca.key"), []byte(sslClientCaKey), 0644); err != nil {
		logger.Debug("❌ maker.ConfigMap: 写入 ssl_client_ca.key 文件: %s 失败, 错误: %v", filepath.Join(dir, "ssl_client_ca.key"), err)
		return err
	}
	logger.Debug("✅ maker.ConfigMap: 写入 ssl_client_ca.key 文件: %s 成功", filepath.Join(dir, "ssl_client_ca.key"))

	// upsert configmap
	logger.Debug("☑️ maker.ConfigMap: 执行 upsert 脚本: %s", filepath.Join(dir, "upsert.sh"))
	if err = os.WriteFile(filepath.Join(dir, "upsert.sh"), []byte(upsert), 0755); err != nil {
		logger.Debug("❌ maker.ConfigMap: 写入 upsert.sh 文件: %s 失败, 错误: %v", filepath.Join(dir, "upsert.sh"), err)
		return err
	}
	logger.Debug("✅ maker.ConfigMap: 写入 upsert.sh 文件: %s 成功", filepath.Join(dir, "upsert.sh"))

	logger.Info("✅ maker.ConfigMap: 构建 ConfigMap 成功!!!")
	return nil
}
