package providers

import (
	"cmdb-backend/models"
	"cmdb-backend/pkg/config"
	"cmdb-backend/pkg/logging"
	utils2 "cmdb-backend/pkg/utils"
	"encoding/json"
	"fmt"
	"github.com/KscSDK/ksc-sdk-go/ksc"
	"github.com/KscSDK/ksc-sdk-go/ksc/utils"
	"github.com/KscSDK/ksc-sdk-go/service/epc"
	"github.com/KscSDK/ksc-sdk-go/service/kec"
	"regexp"
	"strconv"
	"strings"
)

type serverResp struct {
	InstanceCount int
	InstancesSet  []struct {
		InstanceName     string
		InstanceId       string
		AvailabilityZone string
		CreationDate     string
		ImageId          string
		Platform         string
		ProjectId        int
		InstanceType     string
		InstanceState    struct {
			Name string
		}
		InstanceConfigure struct {
			VCPU     int
			MemoryGb int
			GPU      int
		}
		NetworkInterfaceSet []struct {
			PrivateIpAddress string
			PublicIp         string
			SubnetId         string
			VpcId            string
		}
		SystemDisk struct {
			DiskSize int
			DiskType string
		}
		DataDisks []struct {
			DiskSize int
			DiskType string
		}
	}
}

type bmServerResp struct {
	TotalCount int
	HostSet    []struct {
		HostName         string
		HostId           string
		HostStatus       string
		AvailabilityZone string
		CabinetId        string
		CabinetName      string
		CreateTime       string
		HostType         string
		Memory           string
		ImageId          string
		OsName           string
		ProjectId        string
		InstanceType     string
		RackName         string
		RackId           string
		Sn               string
		Cpu              struct {
			CoreCount int
			Model     string
		}
		DiskSet []struct {
			Space    string
			DiskType string
		}
		NetworkInterfaceAttributeSet []struct {
			PrivateIpAddress string
			PublicIp         string
			SubnetId         string
			VpcId            string
		}
	}
}

func kCreateKecClient(region string) (client *kec.Kec) {
	ak := config.GC.Vendor.KsyAk
	sk := config.GC.Vendor.KsySk
	svc := kec.SdkNew(ksc.NewClient(ak, sk), &ksc.Config{Region: &region},
		&utils.UrlInfo{
			UseSSL: true,
		})
	return svc
}

func KsyGetRegionList() {
	client := kCreateKecClient("cn-beijing-6")
	resp, err := client.DescribeRegions(nil)
	if err != nil {
		fmt.Println("[ERROR]", err)
	}
	str, _ := json.Marshal(&resp)
	fmt.Println(string(str))
}

func KsyGetZoneList() {
	regions := models.GetRegionList(1)
	for _, regionId := range regions {
		client := kCreateKecClient(regionId)
		resp, err := client.DescribeAvailabilityZones(nil)
		if err != nil {
			fmt.Println("[ERROR]", err)
		}
		str, _ := json.Marshal(&resp)
		fmt.Println(string(str))
	}
}

func KsyGetVmsList() {
	projectIds := models.GetProjectList(1)
	regions := models.GetRegionList(1)
	for _, projectId := range projectIds {
		for _, regionId := range regions {
			fmt.Println("projectId:", projectId, "regionId:", regionId)
			client := kCreateKecClient(regionId)
			req := map[string]interface{}{
				"MaxResults":  "100",
				"ProjectId.1": projectId,
			}
			resp, err := client.DescribeInstances(&req)
			if err != nil {
				logging.Error("Ksy DescribeInstances API Error", err)
			}

			str, _ := json.Marshal(&resp)
			serverList := serverResp{}
			if err := json.Unmarshal(str, &serverList); err != nil {
				logging.Error("获取主机信息失败", err)
			}

			fmt.Println("服务器总数量", serverList.InstanceCount)
			for _, tmp := range serverList.InstancesSet {
				dataDisk := 0
				for _, disk := range tmp.DataDisks {
					dataDisk += disk.DiskSize
				}

				tmpTime := strings.Trim(tmp.CreationDate, "Z")
				tmpTime = strings.Replace(tmpTime, "T", " ", 1)
				createTime := utils2.Str2Time(tmpTime)

				// 服务器状态
				status := "Unknown"
				if tmp.InstanceState.Name == "active" {
					status = "Running"
				} else if tmp.InstanceState.Name == "stopped" {
					status = "Stopped"
				} else if tmp.InstanceState.Name == "building" {
					status = "Initializing"
				} else {
					status = "Unknown"
				}

				server := models.Server{
					Name:         tmp.InstanceName,
					InstanceId:   tmp.InstanceId,
					InstanceType: "vm",
					VendorId:     1,
					ProjectId:    projectId,
					ImageId:      tmp.ImageId,
					ImageName:    tmp.Platform,
					Status:       status,
					ZoneId:       tmp.AvailabilityZone,
					RegionId:     regionId,
					Cpu:          tmp.InstanceConfigure.VCPU,
					Memory:       tmp.InstanceConfigure.MemoryGb,
					SystemDisk:   tmp.SystemDisk.DiskSize,
					DataDisk:     dataDisk,
					SubnetId:     tmp.NetworkInterfaceSet[0].SubnetId,
					PublicIp:     tmp.NetworkInterfaceSet[0].PublicIp,
					PrivateIp:    tmp.NetworkInterfaceSet[0].PrivateIpAddress,
					BandWith:     0,
					VpcId:        tmp.NetworkInterfaceSet[0].VpcId,
					CreateTime:   createTime,
					//Remark:       "金山云虚拟机",
				}
				fmt.Println(server)
				if err := models.CreateServer(&server, tmp.InstanceId); err != nil {
					logging.Error("更新服务器信息失败", err, map[string]interface{}{"hostName": server.Name})
				}
			}
		}
	}
}

func KsyStartVm(instanceId string, regionId string) (err error) {
	client := kCreateKecClient(regionId)
	startInstances := map[string]interface{}{
		"InstanceId.1": instanceId,
	}
	_, err = client.StartInstances(&startInstances)
	if err != nil {
		logging.Error("Ksy StartInstances API Error", err)
		return err
	}
	return nil
}

func KsyStopVm(instanceId string, regionId string) (err error) {
	client := kCreateKecClient(regionId)
	stopInstances := map[string]interface{}{
		"InstanceId.1": instanceId,
		"ForceStop":    true,
		"StoppedMode":  "StopCharging", // StopCharging:停止计费，KeepCharging:继续计费
	}
	_, err = client.StopInstances(&stopInstances)
	if err != nil {
		logging.Error("Ksy StopInstances API Error", err)
		return err
	}
	return nil
}

func KsyRebootVm(instanceId string, regionId string) (err error) {
	client := kCreateKecClient(regionId)
	rebootInstances := map[string]interface{}{
		"InstanceId.1": instanceId,
		//"ForceReboot":  true, // 强制重启，不建议使用，可能导致数据丢失，而且这样重启机器比较慢。（特殊情况备用）
	}
	_, err = client.RebootInstances(&rebootInstances)
	if err != nil {
		logging.Error("Ksy RebootInstances API Error", err)
		return err
	}
	return nil
}

func KsyDeleteVm(instanceId string, regionId string) (err error) {
	client := kCreateKecClient(regionId)
	terminateInstances := map[string]interface{}{
		"InstanceId.1": instanceId,
		//"ForceDelete":  true, // 强制删除，不经过回收站直接删除。正常会在回收站中保留2个小时，这期间可以进行恢复操作（特殊情况备用）
	}
	_, err = client.TerminateInstances(&terminateInstances)
	if err != nil {
		logging.Error("Ksy TerminateInstances API Error", err)
		return err
	}
	return nil
}

/* 金山云EPC ，裸金属相关代码 */
func kCreateEpcClient(region string) (client *epc.Epc) {
	ak := config.GC.Vendor.KsyAk
	sk := config.GC.Vendor.KsySk
	svc := epc.SdkNew(ksc.NewClient(ak, sk), &ksc.Config{Region: &region},
		&utils.UrlInfo{
			UseSSL: true,
		})
	return svc
}

func KsyGetBmsList() {
	projectIds := models.GetProjectList(1)
	regions := models.GetRegionList(1)
	for _, projectId := range projectIds {
		for _, regionId := range regions {
			fmt.Println("projectId:", projectId, "regionId:", regionId)
			client := kCreateEpcClient(regionId)
			req := map[string]interface{}{
				"MaxResults":  "150",
				"ProjectId.1": projectId,
			}
			resp, err := client.DescribeEpcs(&req)
			if err != nil {
				logging.Error("Ksy DescribeEpcs API Error", err)
			}

			str, _ := json.Marshal(&resp)
			serverList := bmServerResp{}
			if err := json.Unmarshal(str, &serverList); err != nil {
				logging.Error("获取主机信息失败", err, map[string]interface{}{"hostName": serverList.HostSet[0].HostName})
			}

			fmt.Println("服务器总数量", serverList.TotalCount)
			for _, tmp := range serverList.HostSet {
				reg, _ := regexp.Compile("[^0-9]+")
				memory, _ := strconv.Atoi(reg.ReplaceAllString(tmp.Memory, ""))
				systemDisk := 0
				dataDisk := 0
				for _, disk := range tmp.DiskSet {
					if disk.DiskType == "System" {
						systemDisk, _ = strconv.Atoi(reg.ReplaceAllString(disk.Space, ""))
					}
					if disk.DiskType == "Data" {
						dataDisk, _ = strconv.Atoi(reg.ReplaceAllString(disk.Space, ""))
					}
				}

				server := models.Server{
					Name:         tmp.HostName,
					InstanceId:   tmp.HostId,
					InstanceType: "bm",
					VendorId:     1,
					ProjectId:    projectId,
					ImageId:      tmp.ImageId,
					ImageName:    tmp.OsName,
					Status:       tmp.HostStatus,
					ZoneId:       tmp.AvailabilityZone,
					RegionId:     regionId,
					Cpu:          tmp.Cpu.CoreCount,
					CpuModel:     tmp.Cpu.Model,
					Memory:       memory * 1024,
					SystemDisk:   systemDisk,
					DataDisk:     dataDisk * 1024,
					VpcId:        tmp.NetworkInterfaceAttributeSet[0].VpcId,
					SubnetId:     tmp.NetworkInterfaceAttributeSet[0].SubnetId,
					PublicIp:     tmp.NetworkInterfaceAttributeSet[0].PublicIp,
					PrivateIp:    tmp.NetworkInterfaceAttributeSet[0].PrivateIpAddress,
					ModelName:    tmp.HostType,
					CabinetName:  tmp.CabinetName,
					RackName:     tmp.RackName,
					Sn:           tmp.Sn,
					CreateTime:   utils2.Str2Time(tmp.CreateTime),
					//Remark:       "金山云裸金属",
				}
				fmt.Println(server)
				if err := models.CreateServer(&server, tmp.HostId); err != nil {
					logging.Error("更新服务器信息失败", err, map[string]interface{}{"hostName": server.Name})
				}
			}

		}
	}
}

func KsyMaintenanceBms(zone string, title string, content string, instanceId string, attribute string, confirm string) (err error) {
	client := kCreateEpcClient("cn-beijing-6")
	createProcess := map[string]interface{}{
		"MachineCount":     1,
		"Type":             "fix",
		"AvailabilityZone": zone,
		"Title":            title,
		"Content":          content,
		"Confirm":          confirm,
		"Attribute":        attribute,
		"InstanceId":       instanceId,
		"ProcessId":        utils2.RandStringBytes(10),
	}

	_, err = client.CreateProcess(&createProcess)
	if err != nil {
		logging.Error("工单下发失败，请稍后重试或联系管理员。", err)
		return err
	}

	return nil
}

func KsyStartBms(instanceId string, regionId string) (err error) {
	client := kCreateEpcClient(regionId)
	startEpc := map[string]interface{}{
		"HostId": instanceId,
	}
	_, err = client.StartEpc(&startEpc)
	if err != nil {
		logging.Error("Ksy StartEpc API Error", err)
		return err
	}
	return nil
}

func KsyStopBms(instanceId string, regionId string) (err error) {
	client := kCreateEpcClient(regionId)
	stopEpc := map[string]interface{}{
		"HostId": instanceId,
	}
	_, err = client.StopEpc(&stopEpc)
	if err != nil {
		logging.Error("Ksy StopEpc API Error", err)
		return err
	}
	return nil

}

func KsyRebootBms(instanceId string, regionId string) (err error) {
	client := kCreateEpcClient(regionId)
	rebootEpc := map[string]interface{}{
		"HostId": instanceId,
	}
	_, err = client.RebootEpc(&rebootEpc)
	if err != nil {
		logging.Error("Ksy RebootEpc API Error", err)
		return err
	}
	return nil
}

func KsyDeleteBms(instanceId string, regionId string) (err error) {
	client := kCreateEpcClient(regionId)
	deleteEpc := map[string]interface{}{
		"HostId": instanceId,
	}
	_, err = client.DeleteEpc(&deleteEpc)
	if err != nil {
		logging.Error("Ksy DeleteEpc API Error", err)
		return err
	}
	return nil
}
