package service

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"be.ems/src/framework/cmd"
	"be.ems/src/framework/ssh"
	"be.ems/src/framework/utils/file"
	"be.ems/src/framework/utils/parse"
	neModel "be.ems/src/modules/ne/model"
	neService "be.ems/src/modules/ne/service"
	"be.ems/src/modules/ne_data/model"
	systemService "be.ems/src/modules/system/service"
)

// 实例化数据层 Backup 结构体
var NewBackup = &Backup{
	BACKUP_DIR:       "/usr/local/omc/backup",
	sysConfigService: systemService.NewSysConfig,
}

// Backup 备份相关 服务层处理
type Backup struct {
	BACKUP_DIR       string                   // 备份目录
	sysConfigService *systemService.SysConfig // 参数配置服务
}

// FTPConfigUpdate 更新FTP配置信息
func (r Backup) FTPConfigUpdate(value, updateBy string) int64 {
	cfg := r.sysConfigService.FindByKey("neData.backupDataFTP")
	if cfg.ConfigId == 0 {
		return 0
	}
	cfg.ConfigValue = value
	cfg.UpdateBy = updateBy
	return r.sysConfigService.UpdateEncryptValue(cfg)
}

// FTPConfigInfo 获取FTP配置信息
func (r Backup) FTPConfigInfo() model.BackupDataFTP {
	info := model.BackupDataFTP{}
	// 获取配置
	cfg := r.sysConfigService.FindByKeyDecryptValue("neData.backupDataFTP")
	if cfg.ConfigId > 0 && cfg.ConfigValue != "" {
		if err := json.Unmarshal([]byte(cfg.ConfigValue), &info); err != nil {
			return info
		}
	}
	return info
}

// FTPPushFile 推送文件到FTP
func (r Backup) FTPPushFile(localFilePath, tag string) error {
	cfgData := r.FTPConfigInfo()
	if !cfgData.Enable {
		return fmt.Errorf("setting remote backup ftp is disabled")
	}

	connSSH := ssh.ConnSSH{
		User:     cfgData.Username,
		Password: cfgData.Password,
		Addr:     cfgData.ToIp,
		Port:     cfgData.ToPort,
		AuthMode: "0",
	}
	sshClient, err := connSSH.NewClient()
	if err != nil {
		return err
	}
	defer sshClient.Close()
	// 网元主机的SSH客户端进行文件传输
	sftpClient, err := sshClient.NewClientSFTP()
	if err != nil {
		return err
	}
	defer sftpClient.Close()

	remotePath := strings.Replace(localFilePath, r.BACKUP_DIR, tag, 1)
	remotePath = filepath.Join(cfgData.Dir, remotePath)
	// 复制到远程
	if err = sftpClient.CopyFileLocalToRemote(localFilePath, remotePath); err != nil {
		return fmt.Errorf("error uploading file")
	}
	return nil
}

// BackupOMCImport 网元配置文件复制到网元端覆盖
func (r Backup) BackupOMCImport(localZipFile string) error {
	neInfoService := neService.NewNeInfo
	neVersionService := neService.NewNeVersion
	neLicenseService := neService.NewNeLicense
	neConfigBackupService := neService.NewNeConfigBackup

	// 网管本地路径
	omcPath := "/usr/local/omc/backup_omc"
	if runtime.GOOS == "windows" {
		omcPath = fmt.Sprintf("C:%s", omcPath)
	}
	// 解压到临时目录
	omcPathTmp := fmt.Sprintf("%s/import", omcPath)
	if err := file.UnZip(localZipFile, omcPathTmp); err != nil {
		return fmt.Errorf("unzip err")
	}
	defer os.RemoveAll(omcPathTmp) // 删除本地临时目录

	// 还原OMC-网元信息
	neInfos := make([]neModel.NeInfo, 0)       // 网元信息列表
	neVersions := make([]neModel.NeVersion, 0) // 网元版本列表
	neLicenses := make([]neModel.NeLicense, 0) // 网元许可证列表
	neHosts := make([]neModel.NeHost, 0)       // 网元主机列表
	localDirPath := fmt.Sprintf("%s/omc/db", omcPathTmp)
	neInfoStrArr := file.ReadFileJSONLine(fmt.Sprintf("%s/ne_info.json", localDirPath))
	for _, str := range neInfoStrArr {
		var neInfo neModel.NeInfo
		if err := json.Unmarshal([]byte(str), &neInfo); err != nil {
			continue
		}
		neInfos = append(neInfos, neInfo)
	}
	neVersionStrArr := file.ReadFileJSONLine(fmt.Sprintf("%s/ne_version.json", localDirPath))
	for _, str := range neVersionStrArr {
		var neVersion neModel.NeVersion
		if err := json.Unmarshal([]byte(str), &neVersion); err != nil {
			continue
		}
		neVersions = append(neVersions, neVersion)
	}
	neLicenseStrArr := file.ReadFileJSONLine(fmt.Sprintf("%s/ne_license.json", localDirPath))
	for _, str := range neLicenseStrArr {
		var neLicense neModel.NeLicense
		if err := json.Unmarshal([]byte(str), &neLicense); err != nil {
			continue
		}
		neLicenses = append(neLicenses, neLicense)
	}
	neHostStrArr := file.ReadFileJSONLine(fmt.Sprintf("%s/ne_host.json", localDirPath))
	for _, str := range neHostStrArr {
		var neHost neModel.NeHost
		if err := json.Unmarshal([]byte(str), &neHost); err != nil {
			continue
		}
		neHosts = append(neHosts, neHost)
	}
	// 新增网元信息
	for _, neInfo := range neInfos {
		if neInfo.NeId == "" || neInfo.NeType == "OMC" {
			continue
		}
		// 删除网元信息
		neInfoService.FindByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)
		if neInfo.ID > 0 {
			neInfoService.DeleteByIds([]int64{neInfo.ID})
		}

		neVersion := neModel.NeVersion{}
		for _, v := range neVersions {
			if v.NeId == neInfo.NeId && v.NeType == neInfo.NeType {
				v.ID = 0
				neVersion = v
				break
			}
		}
		neLicense := neModel.NeLicense{}
		for _, v := range neLicenses {
			if v.NeId == neInfo.NeId && v.NeType == neInfo.NeType {
				v.ID = 0
				neLicense = v
				break
			}
		}
		neHostArr := make([]neModel.NeHost, 0) // 网元主机列表
		neHostIDs := strings.Split(neInfo.HostIDs, ",")
		for _, hostID := range neHostIDs {
			hostIDNum := parse.Number(hostID)
			for _, v := range neHosts {
				if v.ID == hostIDNum {
					v.ID = 0
					neHostArr = append(neHostArr, v)
				}
			}
		}

		neVersionService.Insert(neVersion)
		neLicenseService.Insert(neLicense)
		neInfo.Hosts = neHostArr
		neInfo.CreateBy = "system"
		neInfoService.Insert(neInfo)
	}

	// 还原网元备份文件
	neList := neInfoService.Find(neModel.NeInfo{}, false, false)
	for _, neInfo := range neList {
		if neInfo.NeType == "OMC" {
			continue
		}
		neTypeLower := strings.ToLower(neInfo.NeType)
		// 配置文件-本地复制到网元端
		localDirPath := fmt.Sprintf("%s/ne_config/%s/%s", omcPathTmp, neTypeLower, neInfo.NeId)
		if err := neConfigBackupService.FileLocalToNePath(neInfo, localDirPath); err != nil {
			continue
		}
	}

	return nil
}

// BackupOMCExport 备份OMC数据导出
func (r Backup) BackupOMCExport() (string, error) {
	neInfoService := neService.NewNeInfo
	neVersionService := neService.NewNeVersion
	neLicenseService := neService.NewNeLicense
	neHostService := neService.NewNeHost
	neConfigBackupService := neService.NewNeConfigBackup

	// 网管本地路径
	omcPath := "/usr/local/omc/backup_omc"
	if runtime.GOOS == "windows" {
		omcPath = fmt.Sprintf("C:%s", omcPath)
	}
	omcPathTmp := fmt.Sprintf("%s/tmp", omcPath)
	defer os.RemoveAll(omcPathTmp) // 删除本地临时目录

	// 备份网元配置文件
	neList := neInfoService.Find(neModel.NeInfo{}, false, false)
	for _, neInfo := range neList {
		if neInfo.NeType == "OMC" {
			continue
		}
		neTypeLower := strings.ToLower(neInfo.NeType)
		// 配置文件-网元端复制到本地
		localDirPath := fmt.Sprintf("%s/ne_config/%s/%s", omcPathTmp, neTypeLower, neInfo.NeId)
		cmd.Execf("sudo mkdir -p %s", localDirPath)
		if err := neConfigBackupService.FileNeToLocalPath(neInfo, localDirPath); err != nil {
			continue
		}
	}

	// 备份OMC
	neInfos := make([]any, 0)    // 网元信息列表
	neVersions := make([]any, 0) // 网元版本列表
	neLicenses := make([]any, 0) // 网元许可证列表
	neHosts := make([]any, 0)    // 网元主机列表
	for _, neInfo := range neList {
		neVersion := neVersionService.FindByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)
		if neVersion.ID > 0 {
			neVersions = append(neVersions, neVersion)
		}
		neLicense := neLicenseService.FindByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)
		if neLicense.ID > 0 {
			neLicenses = append(neLicenses, neLicense)
		}
		neHostIDs := strings.Split(neInfo.HostIDs, ",")
		for _, hostID := range neHostIDs {
			neHost := neHostService.FindById(parse.Number(hostID))
			if neHost.ID > 0 {
				neHosts = append(neHosts, neHost)
			}
		}
		neInfos = append(neInfos, neInfo)
	}
	localDirPath := fmt.Sprintf("%s/omc/db", omcPathTmp)
	cmd.Execf("sudo mkdir -p %s", localDirPath)
	file.WriterFileJSONLine(neInfos, fmt.Sprintf("%s/ne_info.json", localDirPath))
	file.WriterFileJSONLine(neVersions, fmt.Sprintf("%s/ne_version.json", localDirPath))
	file.WriterFileJSONLine(neLicenses, fmt.Sprintf("%s/ne_license.json", localDirPath))
	file.WriterFileJSONLine(neHosts, fmt.Sprintf("%s/ne_host.json", localDirPath))

	// 压缩zip文件名
	zipFileName := fmt.Sprintf("BackupOMC-%s.zip", time.Now().Format("20060102150405"))
	zipFilePath := fmt.Sprintf("%s/%s", omcPath, zipFileName)
	if err := file.CompressZipByDir(zipFilePath, omcPathTmp); err != nil {
		return "", fmt.Errorf("compress zip err")
	}

	return zipFilePath, nil
}
