package main

import (
	"errors"
	"os"
	"path/filepath"
	"slices"
	"strings"

	image2 "wdd.io/agent-common/image"
	"wdd.io/agent-common/utils"
	"wdd.io/agent-deploy/d_app"
	"wdd.io/agent-operator/config"
	"wdd.io/agent-operator/image"
	"wdd.io/agent-operator/minio"
)

const (
	OfflineDeployHarborHost    = "harbor.wdd.io"
	PublicDeployHarborHost     = "42.192.52.227"
	DirectPushDeployHarborHost = "chongqingcis-9b4a3da9.ecis.chongqing-1.cmecloud.cn"

	AllCmiiImageListLocalFileName = "all-cmii-image-list.txt"
	AllGzipImageLocalFileName     = "all-gzip-image-list.txt"
)

type ImageSyncEntity struct {
	DownloadCondition *DownloadEntity // D的条件
	CompressCondition *CompressEntity // C的条件
	UploadCondition   *UploadEntity   // U的条件

	ShouldDownloadFromOss bool // 下载镜像 DLTU中的D
	ShouldUpdateImageTag  bool // 更新镜像 DLTU中的U

	ShouldDirectPushToHarbor bool   // 直接推送到对方的主机 || 离线部署机
	DirectHarborHost         string // IP:Port or 域名:PORT 不带http前缀
}

// DownloadEntity DCU中的D的条件
type DownloadEntity struct {
	ShouldDownloadImage bool // 下载镜像 DCU中的D 实际无用

	ProjectName    string // 优先级3 优先级最低 从DEMO拉取镜像
	ProjectVersion string // 优先级2 高于ProjectName 优先拉取特定版本的镜像

	CmiiNameTagList   []string // 优先级1 appName:tag 会被转换为FullNameImageList
	FullNameImageList []string // 优先级1 优先下载此类型

	DownloadAuthUserName string // 下载需要认证的用户名
	DownloadAuthPassword string // 下载需要认证的密码
}

// CompressEntity DCU中的C的条件
type CompressEntity struct {
	ShouldCompressImageToGzip bool   // 压缩镜像 DCU中的C
	ShouldGzipSplit           bool   // 压缩镜像 是否应该分割存储  true=独立存储 false=整个存储
	GzipLocalFolder           string // 压缩镜像 保存压缩镜像文件的本地目录
}

// UploadEntity DCU中的U的条件
type UploadEntity struct {
	ShouldUploadToDemoMinio bool // 上传镜像 DCU中的U
}

type DirectPushResultEntity struct {
	ErrorPushedImageList []string
}

type ImageSyncResult struct {
	ProcedureSuccessImageList []string // 经过特定步骤之后成功的镜像

	DownloadResult *DownloadResultEntity
	CompressResult *CompressResultEntity
	UploadResult   *UploadResultEntity

	DirectPushResult *DirectPushResultEntity
}

type DownloadResultEntity struct {
	ErrorPullImageList              []string // 下载镜像 DCU中的D 下载失败的镜像
	SuccessPullImageList            []string // 下载镜像 DCU中的D 下载成功的镜像
	SuccessPullTxtFileLocalFullPath string   // 下载镜像 DCU中的D 下载成功的镜像保存的文件地址 GzipLocalFolder + all
}

type CompressResultEntity struct {
	ErrorGzipImageList       []string // 压缩镜像 DCU中的C 压缩失败的镜像
	SuccessGzipImageList     []string // 压缩镜像 DCU中的C 压缩成功的镜像
	GzipTxtFileLocalFullPath string   // 压缩镜像 DCU中的C 压缩镜像保存的目录
}

type UploadResultEntity struct {
	ErrorUploadImageList []string // 上传镜像 DCU中的U 上传失败的镜像
	AllDownloadUrl       []string // 上传镜像 DCU中的U 正式的下载地址列表i
}

// PullFromEntityAndSyncConditionally 根据ImageSyncEntity拉取特定的镜像，然后上传到特定的目标机器(或者上传的minio中)
func (syncCondition *ImageSyncEntity) PullFromEntityAndSyncConditionally() (imageSyncResult *ImageSyncResult) {

	// 初始化 imageSync
	imageSyncResult = &ImageSyncResult{
		ProcedureSuccessImageList: nil,
		DownloadResult: &DownloadResultEntity{
			ErrorPullImageList:              nil,
			SuccessPullImageList:            nil,
			SuccessPullTxtFileLocalFullPath: "",
		},
		CompressResult: &CompressResultEntity{
			ErrorGzipImageList:       nil,
			SuccessGzipImageList:     nil,
			GzipTxtFileLocalFullPath: "",
		},
		UploadResult: &UploadResultEntity{
			ErrorUploadImageList: nil,
			AllDownloadUrl:       nil,
		},
		DirectPushResult: &DirectPushResultEntity{
			ErrorPushedImageList: nil,
		},
	}

	if (syncCondition.DownloadCondition.CmiiNameTagList == nil && syncCondition.DownloadCondition.FullNameImageList == nil) || (len(syncCondition.DownloadCondition.CmiiNameTagList) == 0 && len(syncCondition.DownloadCondition.FullNameImageList) == 0) {
		// 没有指定特定的镜像，那么根据 ProjectVersion 或者从DEMO拉取镜像

		// pull images
		// compress
		if syncCondition.DownloadCondition.ProjectVersion != "" {

			// 获取特定版本的镜像
			C_DownloadCompressUploadFromVersion(syncCondition, imageSyncResult)

		} else {
			// 获取DEMO的镜像
			C_DownloadCompressUploadFromDemo(syncCondition, imageSyncResult)
		}
	} else {
		// 根据列表拉取镜像

		// 组装镜像名称
		syncCondition.DownloadCondition.FullNameImageList = concatAndUniformCmiiImage(syncCondition.DownloadCondition.FullNameImageList, syncCondition.DownloadCondition.CmiiNameTagList)

		// gzip file folder path
		localGzipFolderName := "tmp"
		if syncCondition.DownloadCondition.ProjectName != "" {
			localGzipFolderName = syncCondition.DownloadCondition.ProjectName
		}

		syncCondition.CompressCondition.GzipLocalFolder = filepath.Join(image.OfflineImageGzipFolderPrefix, localGzipFolderName)

		// DCU
		A_DownloadCompressUpload(syncCondition, imageSyncResult)
	}

	// 直接传输到目标Harbor仓库
	if syncCondition.ShouldDirectPushToHarbor {
		if syncCondition.DirectHarborHost == "" {
			log.ErrorF("DirectHarborHost is null ! can't push to target harbor !")
		}
		// push to
		imageSyncResult.DirectPushResult.ErrorPushedImageList = image.TagFromListAndPushToCHarbor(imageSyncResult.ProcedureSuccessImageList, syncCondition.DirectHarborHost)
	}

	// build result

	return imageSyncResult
}

func concatAndUniformCmiiImage(fullImageList []string, cmiiImageList []string) []string {

	if cmiiImageList != nil || len(cmiiImageList) > 0 {
		// cmiiImageList has content
		if fullImageList == nil {
			fullImageList = []string{}
		}

		for _, cmiiImage := range cmiiImageList {
			fullImageList = append(fullImageList, image2.CmiiHarborPrefix+cmiiImage)
		}
	}

	return fullImageList
}

// A_DownloadCompressUpload DCU 镜像同步的前半部分，通常在35.71  LapPro执行，无需Bastion Mode
func A_DownloadCompressUpload(syncEntity *ImageSyncEntity, syncResult *ImageSyncResult) {

	// all image full name list need to download
	fullNameList := syncEntity.DownloadCondition.FullNameImageList

	// Download
	log.Info("[DCU] - DOWNLOAD START !")
	if syncEntity.DownloadCondition.ShouldDownloadImage && fullNameList != nil && len(fullNameList) > 0 {

		syncResult.DownloadResult.ErrorPullImageList = image.PullFromFullNameList(fullNameList)

		// remove failed download image from full name list
		fullNameList = slices.DeleteFunc(fullNameList, func(imageName string) bool {
			return slices.Contains(syncResult.DownloadResult.ErrorPullImageList, imageName)
		})

	} else {
		log.Info("[DCU] - No Need To Download !")
	}

	syncResult.ProcedureSuccessImageList = fullNameList

	gzipLocalFolderPath := syncEntity.CompressCondition.GzipLocalFolder

	localGzipFileListTxt := filepath.Join(gzipLocalFolderPath, AllGzipImageLocalFileName)

	// Compress
	if syncEntity.CompressCondition.ShouldCompressImageToGzip {

		// 移除Gzip的txt
		_ = os.Remove(localGzipFileListTxt)

		// 找到已经存在的压缩文件，跳过
		gzipFileAlready := make(map[string]bool)
		if utils.FileOrFolderExists(gzipLocalFolderPath) {
			dir, _ := os.ReadDir(gzipLocalFolderPath)
			for _, entry := range dir {
				if entry.IsDir() {
					continue
				}
				gzipFileAlready[strings.TrimPrefix(entry.Name(), gzipLocalFolderPath)] = true
			}
		}

		// mkdir folder
		err := os.MkdirAll(gzipLocalFolderPath, os.ModeDir)
		if err != nil {
			if !errors.Is(err, os.ErrExist) {
				log.ErrorF("create folder error of %s", gzipLocalFolderPath)
				panic(err)
			}
		}

		// 循环遍历压缩
		log.Info("[DCU] - COMPRESS START")
		var errorGzipImageList []string
		var allGzipFileFullNameList []string

		if syncEntity.CompressCondition.ShouldGzipSplit {
			// 独立压缩
			for _, imageFullName := range fullNameList {

				// gzip image file already exists
				gzipFileName := image2.ImageFullNameToGzipFileName(imageFullName)
				gzipImageFileFullPath := gzipLocalFolderPath + gzipFileName
				_, ok := gzipFileAlready[gzipFileName]
				if len(gzipFileAlready) > 0 && ok {
					log.DebugF("gzip file %s already exists !", gzipFileName)
				} else {
					ok, gzipImageFileFullPath = image.SaveToGzipFile(imageFullName, gzipLocalFolderPath)
					if !ok {
						errorGzipImageList = append(errorGzipImageList, imageFullName)
						continue
					}
				}

				// 压缩成功
				allGzipFileFullNameList = append(allGzipFileFullNameList, gzipImageFileFullPath)

			}

			syncResult.CompressResult.SuccessGzipImageList = allGzipFileFullNameList
			syncResult.CompressResult.ErrorGzipImageList = errorGzipImageList

			// remove failed
			fullNameList = slices.DeleteFunc(fullNameList, func(imageName string) bool {
				return slices.Contains(errorGzipImageList, imageName)
			})

			// write all gzipped file name to file
			for _, gzipFileFullName := range allGzipFileFullNameList {
				utils.AppendContentToFile(
					strings.TrimPrefix(strings.TrimPrefix(gzipFileFullName, gzipLocalFolderPath), "/")+"\n",
					localGzipFileListTxt,
				)
			}

		} else {
			// 压缩为一个大的压缩包
			gzipFileName := generateMonolithicGzipFileName(syncEntity)

			ok, gzipFileFullPath, errorGzipImageListTmp := image.SaveImageListToGzipFile(fullNameList, gzipLocalFolderPath, gzipFileName)
			if !ok {
				panic("[DCU] - gzip error to a monolithic file !")
			}

			// write all gzipped file name to file
			utils.AppendOverwriteListContentToFile(fullNameList, localGzipFileListTxt)

			// remove failed
			fullNameList = slices.DeleteFunc(fullNameList, func(imageName string) bool {
				return slices.Contains(errorGzipImageListTmp, imageName)
			})

			syncResult.CompressResult.SuccessGzipImageList = fullNameList
			syncResult.CompressResult.ErrorGzipImageList = errorGzipImageListTmp

			log.InfoF("[DCU] - gzip all image from list to monolithic file %s", gzipFileFullPath)
		}

		syncResult.CompressResult.GzipTxtFileLocalFullPath = localGzipFileListTxt

		log.InfoF("[DCU] - all gzip file name list is %s", localGzipFileListTxt)
	}

	syncResult.ProcedureSuccessImageList = fullNameList

	// Upload
	if syncEntity.UploadCondition.ShouldUploadToDemoMinio {
		//uploadGzipFileToDemoMinio()
		// get gzip file name list
		log.Info("[DCU] - UPLOAD OSS START !")

		if !syncEntity.CompressCondition.ShouldCompressImageToGzip {
			// 没有压缩指令 直接上传已有的内容
			allFileInGzipFile, err := utils.ListAllFileInFolderWithFullPath(gzipLocalFolderPath)
			if err != nil {
				log.ErrorF("[DCU] - list all gzip file error !")
				return
			}
			for _, f := range allFileInGzipFile {
				if strings.HasSuffix(f, "tar.gz") {
					syncResult.CompressResult.SuccessGzipImageList = append(syncResult.CompressResult.SuccessGzipImageList, f)
				}
			}

		}

		var errorUploadOssGzipNameList []string
		var allDownloadUrl []string

		// start to upload
		// extract demo oss location suffix from gzipFolderFullPath
		// 根据本地保存Gzip的目录路径提取到 相应的后缀  项目代码
		// projectName / projectVersion
		projectUniqueName := strings.TrimPrefix(gzipLocalFolderPath, image.OfflineImageGzipFolderPrefix)
		projectUniqueName = strings.TrimSuffix(projectUniqueName, "/")

		bucketNameWithPrefix := "cmlc-installation/" + projectUniqueName
		log.InfoF("gzip file location in demo oss is %s", minio.DefaultDemoEndpoint+"/"+bucketNameWithPrefix)

		// 上传所有的压缩文件名称
		if !minio.DefaultCmiiMinioOperator.UploadToDemo(bucketNameWithPrefix, gzipLocalFolderPath, AllGzipImageLocalFileName) {
			log.ErrorF("upload of %s to demo oss error !", AllGzipImageLocalFileName)
		}

		// 上传所有的镜像名称
		if !minio.DefaultCmiiMinioOperator.UploadToDemo(bucketNameWithPrefix, gzipLocalFolderPath, AllCmiiImageListLocalFileName) {
			log.ErrorF("upload of %s to demo oss error !", AllCmiiImageListLocalFileName)
		}

		log.InfoF("upload all gzip file to demo oss !")
		for _, gzipFileFullName := range syncResult.CompressResult.SuccessGzipImageList {
			// SaveToGzipFile 返回的是全路径 归一化处理 gzip file name
			gzipFileName := strings.TrimPrefix(gzipFileFullName, gzipLocalFolderPath)
			gzipFileName = strings.TrimPrefix(gzipFileName, "/")

			if !minio.DefaultCmiiMinioOperator.UploadToDemo(bucketNameWithPrefix, gzipLocalFolderPath, gzipFileName) {
				log.ErrorF("upload of %s to demo oss error !", gzipFileName)
				errorUploadOssGzipNameList = append(errorUploadOssGzipNameList, gzipFileName)
			} else {
				allDownloadUrl = append(allDownloadUrl, minio.DefaultDemoEndpoint+"/"+bucketNameWithPrefix+"/"+gzipFileName)
			}
		}

		syncResult.UploadResult.AllDownloadUrl = allDownloadUrl
		syncResult.UploadResult.ErrorUploadImageList = errorUploadOssGzipNameList

	}

	utils.AppendContentToFile(utils.BeautifulPrintToString(syncResult), filepath.Join(gzipLocalFolderPath, utils.TimeSplitFormatString()+".json"))
}

func generateMonolithicGzipFileName(syncEntity *ImageSyncEntity) string {

	return strings.TrimPrefix(syncEntity.CompressCondition.GzipLocalFolder, image.OfflineImageGzipFolderPrefix) + ".tar.gz"
}

// A_DownloadLoadTagUpload DLTU procedure ImageSync的另外一般流程，需要支持 堡垒机（纯离线）的模式
//  2. Gzip文件目录，RKE MIDDLE CMII三个文件目录 - 约定目录
//     约定目录 /root/wdd/image/rke/  /root/wdd/image/middle/  /root/wdd/image/cmii/
//  3. 读取本机的IP地址 - 参数传递
//  4. OSS地址 - ossUrlPrefix传空  则使用默认值
//  5. ossFileName - 如果结尾为txt，则为文件的形式，如果为tar.gz，则为gzip文件夹的形式
func A_DownloadLoadTagUpload(downloadFromOss bool, ossUrlPrefix, ossFileNameOrGzipFileListTxt, localGzipFolderOrGzipFile string, targetHarborFullName string) (targetImageFullNameList []string) {

	// 支持单文件的形式
	if !utils.IsDirOrFile(localGzipFolderOrGzipFile) {
		// 单个压缩文件 肯定是离线的形式
		if !strings.HasSuffix(localGzipFolderOrGzipFile, ".tar.gz") {
			log.ErrorF("local gzip file %s is not a .tar.gz file !", localGzipFolderOrGzipFile)
			return nil
		}

		// load
		image.LoadFromGzipFilePath(localGzipFolderOrGzipFile)
	} else {
		separator := os.PathSeparator
		if !strings.HasSuffix(localGzipFolderOrGzipFile, string(separator)) {
			localGzipFolderOrGzipFile += string(separator)
		}

		// download
		if downloadFromOss {
			if !parseAndDownloadFromOss(ossUrlPrefix, ossFileNameOrGzipFileListTxt, localGzipFolderOrGzipFile) {
				log.ErrorF("download from oss error !")
				return nil
			}
		}

		// load
		loadAllGzipImageFromLocalFolder(localGzipFolderOrGzipFile)
	}

	// tag
	// push
	allFileInFolder, err := utils.ListAllFileInFolder(localGzipFolderOrGzipFile)
	if err != nil {
		return nil
	}
	for _, gzipFileName := range allFileInFolder {
		// 过滤非.tar.gz结尾的文件
		if !strings.HasSuffix(gzipFileName, ".tar.gz") {
			continue
		}

		log.DebugF("gzip file name is %s", gzipFileName)

		// gzip to image full name 拿到镜像的原始名称
		imageFullName := image2.GzipFileNameToImageFullName(gzipFileName)
		if imageFullName == "" {
			log.ErrorF("gzip file  %s to image full name error !", gzipFileName)
			continue
		}

		// tag 拿到目标名称 然后重新Tag
		targetImageFullName := image2.ImageNameToTargetImageFullName(imageFullName, targetHarborFullName)
		image.TagFromSourceToTarget(imageFullName, targetImageFullName)

		// uploadToHarbor 上传到目标Harbor
		if image.UploadToHarbor(targetImageFullName) {
			targetImageFullNameList = append(targetImageFullNameList, targetImageFullName)
		} else {
			log.ErrorF("upload to harbor error of %s", targetImageFullName)
		}
	}

	return targetImageFullNameList
}

func loadAllGzipImageFromLocalFolder(localGzipFolder string) {
	image.LoadFromFolderPath(localGzipFolder)
}

func parseAndDownloadFromOss(ossUrlPrefix, ossFileName, localGzipFolder string) bool {

	if ossUrlPrefix == "" {
		ossUrlPrefix = minio.DefaultOssUrlPrefix
	}
	if !strings.HasSuffix(ossUrlPrefix, "/") {
		ossUrlPrefix += "/"
	}

	log.InfoF("prepare to download from %s%s", ossUrlPrefix, ossFileName)

	if !minio.DefaultCmiiMinioOperator.DemoMinioOperator.DownloadFileFromOssFullUrl(ossUrlPrefix+ossFileName, localGzipFolder) {
		log.ErrorF("download %s from oss error !", ossUrlPrefix+ossFileName)
		return false
	}

	if strings.HasSuffix(ossFileName, ".txt") {
		// download from gzip file list txt
		// download all files in the txt file
		result := utils.ReadAllContentFromFile(localGzipFolder + ossFileName)
		for _, gzipFileName := range result {
			minio.DefaultCmiiMinioOperator.DemoMinioOperator.DownloadFileFromOssFullUrl(ossUrlPrefix+gzipFileName, localGzipFolder)
		}
	}

	// 解析
	return true
}

// C_DownloadCompressUploadFromDemo 获取DEMO环境的全部镜像
func C_DownloadCompressUploadFromDemo(syncEntity *ImageSyncEntity, syncResult *ImageSyncResult) {

	// generate a project folder
	projectName := syncEntity.DownloadCondition.ProjectName
	gzipFolderLocalPath := filepath.Join(image.OfflineImageGzipFolderPrefix, projectName)

	err := os.MkdirAll(gzipFolderLocalPath, os.ModeDir)
	if err != nil {
		if !errors.Is(err, os.ErrExist) {
			log.ErrorF("[Download_Compress_Upload_From_Demo] - create folder of %s error %s", gzipFolderLocalPath, err.Error())

		}
	}

	// get demo image version map
	allCmiiImageFullNameList := buildAllCmiiImageNameListFromDemo(projectName)

	// save all cmii image to file
	allPullImageNameTxtFileName := filepath.Join(gzipFolderLocalPath, AllCmiiImageListLocalFileName)
	utils.AppendOverwriteListContentToFile(allCmiiImageFullNameList, allPullImageNameTxtFileName)

	syncEntity.CompressCondition.GzipLocalFolder = gzipFolderLocalPath
	syncEntity.DownloadCondition.FullNameImageList = allCmiiImageFullNameList

	// save to result
	syncResult.DownloadResult.SuccessPullTxtFileLocalFullPath = allPullImageNameTxtFileName

	// do work
	// DCU
	A_DownloadCompressUpload(syncEntity, syncResult)
}

func buildAllCmiiImageNameListFromDemo(projectName string) []string {

	var realCmiiImageName []string

	backendMap, frontendMap, srsMap := BackupAllCmiiDeploymentToMap(config.Demo)

	// save map to file
	backendMapFile := image.OfflineImageGzipFolderPrefix + projectName + "-backend-app.json"
	frontendMapFile := image.OfflineImageGzipFolderPrefix + projectName + "-frontend-app.json"
	srsMapFile := image.OfflineImageGzipFolderPrefix + projectName + "-srs-app.json"
	_ = os.Remove(backendMapFile)
	_ = os.Remove(frontendMapFile)
	_ = os.Remove(srsMapFile)

	//utils.AppendContentToFile(
	//	utils.BeautifulPrintToString(backendMap),
	//	backendMapFile,
	//)
	//utils.AppendContentToFile(
	//	utils.BeautifulPrintToString(frontendMap),
	//	frontendMapFile,
	//)
	//utils.AppendContentToFile(
	//	utils.BeautifulPrintToString(srsMapFile),
	//	srsMapFile,
	//)

	realCmiiImageName = append(realCmiiImageName, image.CmiiImageMapToFullNameList(backendMap)...)
	realCmiiImageName = append(realCmiiImageName, image.CmiiImageMapToFullNameList(frontendMap)...)
	realCmiiImageName = append(realCmiiImageName, image.CmiiImageMapToFullNameList(srsMap)...)

	utils.BeautifulPrintListWithTitle(realCmiiImageName, "Cmii Project Image => "+projectName)

	return realCmiiImageName
}

// C_DownloadCompressUploadFromVersion 根据版本下载全部的CMII镜像
func C_DownloadCompressUploadFromVersion(syncEntity *ImageSyncEntity, syncResult *ImageSyncResult) {

	// generate a project folder
	projectCmiiVersion := syncEntity.DownloadCondition.ProjectVersion

	// gzip local path
	gzipFolderLocalPath := filepath.Join(image.OfflineImageGzipFolderPrefix, projectCmiiVersion)

	err := os.MkdirAll(gzipFolderLocalPath, os.ModeDir)
	if err != nil {
		if !errors.Is(err, os.ErrExist) {
			log.ErrorF("[Download_Compress_Upload_From_Demo] - create folder of %s error %s", gzipFolderLocalPath, err.Error())
		}
	}

	syncEntity.CompressCondition.GzipLocalFolder = gzipFolderLocalPath

	// build all cmii image name list
	allCmiiImageFullNameList := buildAllCmiiImageNameListFromVersion(projectCmiiVersion)
	// assign
	syncEntity.DownloadCondition.FullNameImageList = allCmiiImageFullNameList

	// save all cmii image to file
	allImageListTxtFileFullName := filepath.Join(gzipFolderLocalPath, AllCmiiImageListLocalFileName)
	utils.AppendOverwriteContentToFile(utils.BeautifulPrintToString(allCmiiImageFullNameList), allImageListTxtFileFullName)

	// save to result
	syncResult.DownloadResult.SuccessPullTxtFileLocalFullPath = allImageListTxtFileFullName

	// do work
	// DCU procedure
	A_DownloadCompressUpload(syncEntity, syncResult)
}

// buildAllCmiiImageNameListFromVersion 根据VersionTag构建完整的应用名称列表
func buildAllCmiiImageNameListFromVersion(cmiiVersion string) []string {

	var realCmiiImageName []string

	backendMap := d_app.CmiiBackendAppMap
	frontendMap := d_app.CmiiFrontendAppMap

	for app := range backendMap {
		backendMap[app] = cmiiVersion
	}
	for app := range frontendMap {
		frontendMap[app] = cmiiVersion
	}

	realCmiiImageName = append(realCmiiImageName, image.CmiiImageMapToFullNameList(backendMap)...)
	realCmiiImageName = append(realCmiiImageName, image.CmiiImageMapToFullNameList(frontendMap)...)

	for key, value := range d_app.CmiiSrsAppMap {
		var app *config.CmiiDeploymentInterface
		if strings.Contains(value, "deployment") {
			app = DefaultCmiiOperator.DeploymentOneInterface(config.Demo, key)
			if app != nil {
				realCmiiImageName = append(realCmiiImageName, app.Image)
			}
		} else if strings.Contains(value, "state") {
			app = DefaultCmiiOperator.StatefulSetOneInterface(config.Demo, key)
			if app != nil {
				for _, imageName := range app.ContainerImageMap {
					realCmiiImageName = append(realCmiiImageName, imageName)
				}
			}
		}
	}
	utils.BeautifulPrintListWithTitle(realCmiiImageName, "Cmii Version Image => "+cmiiVersion)
	return realCmiiImageName
}

// C_DownloadCompressUploadDependency DCU所有的依赖镜像
func C_DownloadCompressUploadDependency(shouldGzip bool, shouldOss bool, isRKE bool) (errorPullImageList, errorGzipImageList, realCmiiImageName, allGzipFileNameList []string) {

	log.Info("DCU for middle and rke!")
	err := os.MkdirAll(image.OfflineImageGzipFolderPrefix, os.ModeDir)
	if err != nil {
		if !errors.Is(err, os.ErrExist) {
			log.ErrorF("[FetchDependencyRepos] - create folder of %s error %s", image.OfflineImageGzipFolderPrefix, err.Error())
		}
	}

	var fullImageNameList []string
	var gzipFolderPrefix string

	if isRKE {
		log.Info("DCU for rke!")
		fullImageNameList = d_app.Rancher13014Amd64
		gzipFolderPrefix = image.OfflineImageGzipFolderPrefix + "rke13014/"
	} else {
		log.Info("DCU for middle!")

		fullImageNameList = d_app.MiddlewareAmd64
		gzipFolderPrefix = image.OfflineImageGzipFolderPrefix + "middle/"
	}

	syncEntity := &ImageSyncEntity{
		DownloadCondition: &DownloadEntity{
			ShouldDownloadImage:  true,
			ProjectName:          "",
			ProjectVersion:       "",
			CmiiNameTagList:      nil,
			FullNameImageList:    fullImageNameList,
			DownloadAuthUserName: "",
			DownloadAuthPassword: "",
		},
		CompressCondition: &CompressEntity{
			ShouldCompressImageToGzip: shouldGzip,
			ShouldGzipSplit:           true,
			GzipLocalFolder:           gzipFolderPrefix,
		},
		UploadCondition:          &UploadEntity{ShouldUploadToDemoMinio: shouldOss},
		ShouldDownloadFromOss:    false,
		ShouldUpdateImageTag:     false,
		ShouldDirectPushToHarbor: false,
		DirectHarborHost:         "",
	}

	syncResult := &ImageSyncResult{
		ProcedureSuccessImageList: nil,
		DownloadResult: &DownloadResultEntity{
			ErrorPullImageList:              nil,
			SuccessPullImageList:            nil,
			SuccessPullTxtFileLocalFullPath: "",
		},
		CompressResult: &CompressResultEntity{
			ErrorGzipImageList:       nil,
			SuccessGzipImageList:     nil,
			GzipTxtFileLocalFullPath: "",
		},
		UploadResult: &UploadResultEntity{
			ErrorUploadImageList: nil,
			AllDownloadUrl:       nil,
		},
	}

	utils.AppendOverwriteListContentToFile(fullImageNameList, filepath.Join(gzipFolderPrefix, AllCmiiImageListLocalFileName))

	A_DownloadCompressUpload(syncEntity, syncResult)

	return syncResult.DownloadResult.ErrorPullImageList, syncResult.CompressResult.ErrorGzipImageList, syncResult.ProcedureSuccessImageList, syncResult.CompressResult.SuccessGzipImageList
}

func LoadSplitCmiiGzipImageToTargetHarbor(projectName, targetHarborHost string) (errorLoadImageNameList, errorPushImageNameList []string) {

	// list folder
	projectGzipFolder := image.OfflineImageGzipFolderPrefix + projectName
	errorLoadImageNameList = append(errorLoadImageNameList, image.LoadFromFolderPath(projectGzipFolder)...)
	// read from json
	errorPushImageNameList = append(errorPushImageNameList, image.TagFromListAndPushToCHarbor(d_app.Cmii520DemoImageList, targetHarborHost)...)

	// re-tag
	// push

	// todo clean host and harbor
	// check harbor exits

	return errorLoadImageNameList, errorPushImageNameList
}

func LoadSplitDepGzipImageToTargetHarbor(targetHarborHost string) (errorLoadImageNameList []string, errorPushImageNameList []string) {

	errorPushImageNameList = append(errorPushImageNameList, image.TagFromListAndPushToCHarbor(d_app.MiddlewareAmd64, targetHarborHost)...)
	//errorPushImageNameList = append(errorPushImageNameList, image.TagFromListAndPushToCHarbor(d_app.Rancher1204Amd64, targetHarborHost)...)

	return errorLoadImageNameList, errorPushImageNameList

}
