package main

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"wdd.io/agent-common/logger"

	image2 "wdd.io/agent-common/image"
	"wdd.io/agent-common/utils"
	agentdeploy "wdd.io/agent-deploy"
	"wdd.io/agent-deploy/z_dep"
	"wdd.io/agent-operator/image"
)

var DeployFilePrefix = "/root/wddproject/WddSuperAgent/agent-common/real_project/"

var log = logger.Log

func init() {
	switch runtime.GOOS {
	case "linux":
		DeployFilePrefix = "/root/wddproject/WddSuperAgent/agent-common/real_project/"
	case "windows":
		//DeployFilePrefix = "C:\\Users\\wdd\\Documents\\IdeaProjects\\WddSuperAgent\\agent-common\\real_project\\"
		DeployFilePrefix = "C:\\Users\\wddsh\\Documents\\IdeaProjects\\WddSuperAgent\\agent-common\\real_project\\"

	}
}

// CmiiEnvDeploy 根据特定的环境复制一份部署清单，复制Cmii App的部署 shouldDoCompleteDeploy决定是否生成其他的应用
func CmiiEnvDeploy(
	deployCommonEnv *z_dep.CommonEnvironmentConfig,
	shouldDoCompleteDeploy bool,
	backupFromEnv string,
) {

	folderPrefix := DeployFilePrefix + deployCommonEnv.Namespace + "/"

	tenantEnv := deployCommonEnv.Namespace
	//uavcloud-devflight ==> devflight
	//uavcloud-dev       ==> dev
	if strings.Contains(tenantEnv, "-") {
		split := strings.Split(tenantEnv, "-")
		tenantEnv = split[len(split)-1]
	} else {
		// demo ==> ""
		// cqlyj ==> ""
		tenantEnv = ""
	}

	// assign folder prefix
	deployCommonEnv.ApplyFilePrefix = folderPrefix
	deployCommonEnv.TenantEnv = tenantEnv

	var backendMap map[string]string
	var frontendMap map[string]string
	var srsMap map[string]string

	// 输出特定版本的Tag
	backendMap, frontendMap, srsMap = image.GenerateCmiiTagVersionImageMap(deployCommonEnv.TagVersion)

	if backupFromEnv != "" {
		//  从 backupFromEnv 环境拉取特定版本的所有Tag
		backendMapFromEnv, frontendMapFromEnv, srsMapFromEnv := BackupAllCmiiDeploymentToMap(backupFromEnv)

		backendMap = utils.MergeMap(backendMap, backendMapFromEnv)
		frontendMap = utils.MergeMap(frontendMap, frontendMapFromEnv)
		srsMap = utils.MergeMap(srsMap, srsMapFromEnv)
	}

	utils.BeautifulPrintWithTitle(backendMap, "backendMap")
	utils.BeautifulPrintWithTitle(frontendMap, "frontendMap")
	utils.BeautifulPrintWithTitle(srsMap, "srsMap")

	// get the apply file path
	deployCommonEnv.GenerateApplyFilePath()

	// do generate all application files
	// generate and get all old stuff
	agentdeploy.CmiiEnvironmentDeploy(shouldDoCompleteDeploy, deployCommonEnv, backendMap, frontendMap)

	// test
	//GetNodeWideByKubectl(deployNamespace)

	// clear old apply file
	//clearOldApplyStuff(common, shouldDoCompleteDeploy)

	// apply new app
	//applyNewAppStuff(common, shouldDoCompleteDeploy)

	fmt.Println()
	fmt.Println("-------------------- all done ---------------------")
	fmt.Println()

}

func CmiiEnvDeployOffline(deployCommonEnv *z_dep.CommonEnvironmentConfig, shouldDoCompleteDeploy bool, allCmiiImageList []string) {
	folderPrefix := DeployFilePrefix + deployCommonEnv.Namespace + "/"

	tenantEnv := deployCommonEnv.Namespace
	// uavcloud-devflight ==> devflight
	// uavcloud-dev       ==> dev
	if strings.Contains(tenantEnv, "-") {
		split := strings.Split(tenantEnv, "-")
		tenantEnv = split[len(split)-1]
	} else {
		// demo ==> ""
		// cqlyj ==> ""
		tenantEnv = ""
	}

	// assign folder prefix
	deployCommonEnv.ApplyFilePrefix = folderPrefix
	deployCommonEnv.TenantEnv = tenantEnv

	var backendMap map[string]string
	var frontendMap map[string]string
	var srsMap map[string]string

	// 输出特定版本的Tag
	cmiiImageVersionMap := image2.CmiiImageMapFromImageFullNameList(allCmiiImageList)
	frontendMap, backendMap, srsMap = image2.FrontendBackendSrsImageMapFromCmiiImageMap(cmiiImageVersionMap)

	utils.BeautifulPrintWithTitle(backendMap, "backendMap")
	utils.BeautifulPrintWithTitle(frontendMap, "frontendMap")
	utils.BeautifulPrintWithTitle(srsMap, "srsMap")

	// get the apply file path
	deployCommonEnv.GenerateApplyFilePath()

	// do generate all application files
	// generate and get all old stuff
	agentdeploy.CmiiEnvironmentDeploy(shouldDoCompleteDeploy, deployCommonEnv, backendMap, frontendMap)

	// test
	//GetNodeWideByKubectl(deployNamespace)

	// clear old apply file
	//clearOldApplyStuff(common, shouldDoCompleteDeploy)

	// apply new app
	//applyNewAppStuff(common, shouldDoCompleteDeploy)

	fmt.Println()
	fmt.Println("-------------------- all done ---------------------")
	fmt.Println()
}

func CmiiNewAppDeploy(deployCommonEnv *z_dep.CommonEnvironmentConfig, newAppNamespace string) {
	folderPrefix := DeployFilePrefix + deployCommonEnv.Namespace + "/"

	tenantEnv := deployCommonEnv.Namespace
	// uavcloud-devflight ==> devflight
	// uavcloud-dev       ==> dev
	if strings.Contains(tenantEnv, "-") {
		split := strings.Split(tenantEnv, "-")
		tenantEnv = split[len(split)-1]
	} else {
		// demo ==> ""
		// cqlyj ==> ""
		tenantEnv = ""
	}

	// assign folder prefix
	deployCommonEnv.ApplyFilePrefix = folderPrefix

	deployCommonEnv.TenantEnv = tenantEnv

	var backendMap map[string]string
	var frontendMap map[string]string
	var srsMap map[string]string

	// 输出特定版本的Tag
	backendMap, frontendMap, srsMap = image.GenerateCmiiTagVersionImageMap(deployCommonEnv.TagVersion)

	if newAppNamespace != "" {
		//  从 backupFromEnv 环境拉取特定版本的所有Tag
		backendMapFromEnv, frontendMapFromEnv, srsMapFromEnv := BackupAllCmiiDeploymentToMap(newAppNamespace)

		backendMap = utils.MergeMap(backendMap, backendMapFromEnv)
		frontendMap = utils.MergeMap(frontendMap, frontendMapFromEnv)
		srsMap = utils.MergeMap(srsMap, srsMapFromEnv)
	}

	utils.BeautifulPrintWithTitle(backendMap, "backendMap")
	utils.BeautifulPrintWithTitle(frontendMap, "frontendMap")
	utils.BeautifulPrintWithTitle(srsMap, "srsMap")

	// get the apply file path
	deployCommonEnv.GenerateApplyFilePath()

	// generate application file
	agentdeploy.CmiiNewAppDeploy(deployCommonEnv, backendMap, frontendMap)

	// apply file
	applyNewAppStuff(deployCommonEnv, false)

}

func applyNewAppStuff(common *z_dep.CommonEnvironmentConfig, shouldDoCompleteDeploy bool) bool {
	files, err := os.ReadDir(common.ApplyFilePrefix)
	if err != nil {
		log.ErrorF("failed to read directory: %v", err)
		return false
	}
	if len(files) == 0 {
		log.WarnF("no apply file found in %s", common.ApplyFilePrefix)
		return false
	}

	namespace := common.Namespace

	if shouldDoCompleteDeploy {

		// pvc
		ApplyByKubectl(z_dep.PVCApplyFilePath, namespace)

		// mysql
		ApplyByKubectl(z_dep.MySQLApplyFilePath, namespace)
		if !DefaultCmiiOperator.PodStatusCheckTimeout("helm-mysql-0", namespace, 180) {
			return false
		}

		// mongo
		ApplyByKubectl(z_dep.MongoApplyFilePath, namespace)
		if !DefaultCmiiOperator.PodStatusCheckTimeout("helm-mongo-0", namespace, 180) {
			return false
		}

		// redis
		ApplyByKubectl(z_dep.RedisApplyFilePath, namespace)
		if !DefaultCmiiOperator.PodStatusCheckTimeout("helm-redis-master-0", namespace, 180) {
			return false
		}
		if !DefaultCmiiOperator.PodStatusCheckTimeout("helm-redis-replicas-0", namespace, 180) {
			return false
		}

		// rabbitmq
		ApplyByKubectl(z_dep.RabbitMQApplyFilePath, namespace)
		if !DefaultCmiiOperator.PodStatusCheckTimeout("helm-rabbitmq-0", namespace, 180) {
			return false
		}

		// nacos
		ApplyByKubectl(z_dep.NacosApplyFilePath, namespace)
		if !DefaultCmiiOperator.PodStatusCheckTimeout("helm-nacos-0", namespace, 180) {
			return false
		}

	}

	// frontend
	ApplyByKubectl(z_dep.IngresApplyFilePath, namespace)
	ApplyByKubectl(z_dep.ConfigMapApplyFilePath, namespace)
	ApplyByKubectl(z_dep.FrontendApplyFilePath, namespace)

	// backend
	ApplyByKubectl(z_dep.BackendApplyFilePath, namespace)

	// srs
	ApplyByKubectl(z_dep.SRSApplyFilePath, namespace)

	return true
}

func clearOldApplyStuff(common *z_dep.CommonEnvironmentConfig, shouldDoCompleteDeploy bool) bool {

	oldApplyFilePath := filepath.Join(common.ApplyFilePrefix, "old")
	files, err := os.ReadDir(oldApplyFilePath)
	if err != nil {
		log.ErrorF("failed to read directory: %v", err)
		return false
	}
	if len(files) == 0 {
		log.WarnF("no apply file found in %s", common.ApplyFilePrefix)
		return false
	}

	namespace := common.Namespace

	for _, fileEntry := range files {
		switch fileEntry.Name() {
		case z_dep.PVCApplyFileName:
			continue
		case z_dep.MySQLApplyFileName:
			continue
		case z_dep.MongoApplyFileName:
			continue
		case z_dep.RedisApplyFileName:
			continue
		case z_dep.RabbitMQApplyFileName:
			continue
		case z_dep.EmqxApplyFileName:
			continue
		case z_dep.NacosApplyFileName:
			continue
		case z_dep.ConfigMapApplyFileName:
			continue
		case z_dep.IngresApplyFileName:
			continue
		default:
			log.InfoF("[clearOldApplyStuff] - delete %s", fileEntry.Name())
			DeleteByKubectl(filepath.Join(oldApplyFilePath, fileEntry.Name()), namespace)
		}
	}

	return true
}
