package v1

import (
	"cmdb-backend/models"
	"cmdb-backend/pkg/utils"
	"cmdb-backend/providers"
	"github.com/gin-gonic/gin"
	"net/http"
	"strconv"
)

type OpServerInfo struct {
	Id          int      `json:"id"`
	App         string   `json:"app"`
	Owner       string   `json:"owner"`
	Remark      string   `json:"remark"`
	InstanceIds []string `json:"instance_ids"`
	ServerIds   []int    `json:"server_ids"`
}

type maintenanceInfo struct {
	Title     string `json:"title"`
	Content   string `json:"content"`
	Confirm   string `json:"confirm"`
	Attribute string `json:"attribute"`
	Items     []struct {
		Name       string `json:"name"`
		Zone       string `json:"zone"`
		InstanceId string `json:"instance_id"`
	}
}

func GetServerList(c *gin.Context) {
	key := c.Query("key")
	status := c.Query("status")
	zoneId := c.Query("zone_id")
	regionId := c.Query("region_id")
	projectId := c.Query("project_id")
	instanceType := c.Query("instance_type")
	vendorId, _ := strconv.Atoi(c.Query("vendor_id"))
	pageNum, _ := strconv.Atoi(c.Query("page_number"))
	pageSize, _ := strconv.Atoi(c.Query("page_size"))

	serverList := models.GetServer(key, projectId, vendorId, status, zoneId, regionId, instanceType, utils.GetPage(pageNum, pageSize), pageSize)
	total := models.GetServerTotal(key, projectId, vendorId, status, zoneId, regionId, instanceType)

	c.JSON(http.StatusOK, utils.AmisResponse{
		Data: map[string]interface{}{
			"items": serverList,
			"total": total,
		},
	})
}

func GetServerDetail(c *gin.Context) {
	serverId, _ := strconv.Atoi(c.Param("id"))
	serverDetail := models.GetServerDetail(serverId)
	c.JSON(http.StatusOK, utils.AmisResponse{
		Data: serverDetail,
	})
}

func CreateServer(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"result": "ok!"})
}

func UpdateServer(c *gin.Context) {
	query := OpServerInfo{}
	if err := c.ShouldBindJSON(&query); err != nil {
		utils.AmisError(c, "数据格式不正确，请修改后重新提交。")
		return
	}

	if err := models.UpdateServer(query.Id, query.App, query.Owner, query.Remark, query.ServerIds); err != nil {
		utils.AmisError(c, "update server owner failed !")
		return
	}
	c.JSON(http.StatusOK, utils.AmisResponse{
		Msg: "服务器信息修改成功。",
	})
}

func DeleteServer(c *gin.Context) {
	query := OpServerInfo{}
	if err := c.ShouldBindJSON(&query); err != nil {
		utils.AmisError(c, "数据格式不正确，请修改后重新提交。")
		return
	}

	for _, serverId := range query.ServerIds {
		// 根据 server_id 获取主机信息，方便后续调用厂商接口删除主机
		serverDetail := models.GetServerDetail(serverId)
		vendorId := serverDetail.VendorId
		serverType := serverDetail.InstanceType
		instanceId := serverDetail.InstanceId
		projectId := serverDetail.ProjectId
		regionId := serverDetail.RegionId

		/* 主要逻辑：
		1. 根据 vendorId 和 serverType 做判断，调对应厂商的 API 删除主机「 目前仅支持金山云(1)、Ucloud(2) 」
		2. 修改数据库中的记录为 Deleted, 留个记录 */

		if vendorId == 1 {
			// 金山裸金属和虚拟机删除接口不同，要增加 serverType 判断
			if serverType == "vm" {
				if err := providers.KsyDeleteVm(instanceId, regionId); err != nil {
					utils.AmisError(c, err)
					return
				}
			} else {
				if err := providers.KsyDeleteBms(instanceId, regionId); err != nil {
					utils.AmisError(c, err)
					return
				}
			}
		} else if vendorId == 2 {
			// Ucloud 只有虚拟机
			if err := providers.UcloudDeleteVm(instanceId, regionId, projectId); err != nil {
				utils.AmisError(c, err)
				return
			}
		} else {
			// TODO 补充其他厂商删除操作, 如 IDC 等
			utils.AmisError(c, "暂不支持该厂商删除操作。")
			return
		}

		// 修改数据库中的记录为 Deleted, 留个记录
		if err := models.UpdateServerStatus(serverId, "Deleted"); err != nil {
			utils.AmisError(c, err)
			return
		}
	}

	c.JSON(http.StatusOK, utils.AmisResponse{
		Msg: "服务器删除成功。",
	})
}

func StartServer(c *gin.Context) {
	query := OpServerInfo{}
	if err := c.ShouldBindJSON(&query); err != nil {
		utils.AmisError(c, "数据格式不正确，请修改后重新提交。")
		return
	}

	for _, serverId := range query.ServerIds {
		// 根据 server_id 获取主机信息，方便后续调用厂商接口开机
		serverDetail := models.GetServerDetail(serverId)
		vendorId := serverDetail.VendorId
		serverType := serverDetail.InstanceType
		instanceId := serverDetail.InstanceId
		projectId := serverDetail.ProjectId
		regionId := serverDetail.RegionId

		/* 主要逻辑：
		1. 根据 vendorId 和 serverType 做判断，调对应厂商的 API 开机，目前仅支持金山云(1)、Ucloud(2)
		2. 修改数据库中的记录状态为 Running */

		if vendorId == 1 {
			// 金山裸金属和虚拟机开机接口不同，要增加 serverType 判断
			if serverType == "vm" {
				if err := providers.KsyStartVm(instanceId, regionId); err != nil {
					utils.AmisError(c, err)
					return
				}
			} else {
				if err := providers.KsyStartBms(instanceId, regionId); err != nil {
					utils.AmisError(c, err)
					return
				}
			}
		} else if vendorId == 2 {
			if err := providers.UcloudStartVm(instanceId, regionId, projectId); err != nil {
				utils.AmisError(c, err)
				return
			}
		} else {
			//TODO 补充其他厂商删除操作, 如 IDC 等
			utils.AmisError(c, "暂不支持该厂商启动操作。")
			return
		}

		// 更新数据库记录
		if err := models.UpdateServerStatus(serverId, "Running"); err != nil {
			utils.AmisError(c, "update server status failed !")
			return
		}
	}

	c.JSON(http.StatusOK, utils.AmisResponse{
		Msg: "服务器开启成功。",
	})
}

func StopServer(c *gin.Context) {
	query := OpServerInfo{}
	if err := c.ShouldBindJSON(&query); err != nil {
		utils.AmisError(c, "数据格式不正确，请修改后重新提交。")
		return
	}

	for _, serverId := range query.ServerIds {
		// 根据 server_id 获取主机信息，方便后续调用厂商接口关机
		serverDetail := models.GetServerDetail(serverId)
		vendorId := serverDetail.VendorId
		serverType := serverDetail.InstanceType
		instanceId := serverDetail.InstanceId
		projectId := serverDetail.ProjectId
		regionId := serverDetail.RegionId

		/* 主要逻辑：
		1. 根据 vendorId 和 serverType 做判断，调对应厂商的 API 关机，目前仅支持金山云(1)、Ucloud(2)
		2. 修改数据库中的记录状态为 Stopped */

		if vendorId == 1 {
			// 金山裸金属和虚拟机关机接口不同，要增加 serverType 判断
			if serverType == "vm" {
				if err := providers.KsyStopVm(instanceId, regionId); err != nil {
					utils.AmisError(c, err)
					return
				}
			} else {
				if err := providers.KsyStopBms(instanceId, regionId); err != nil {
					utils.AmisError(c, err)
					return
				}
			}
		} else if vendorId == 2 {
			if err := providers.UcloudStopVm(instanceId, regionId, projectId); err != nil {
				utils.AmisError(c, err)
				return
			}
		} else {
			//TODO 补充其他厂商删除操作, 如 IDC 等
			utils.AmisError(c, "暂不支持该厂商关机操作。")
		}

		// 更新数据库记录
		if err := models.UpdateServerStatus(serverId, "Stopped"); err != nil {
			utils.AmisError(c, "update server status failed !")
			return
		}
	}

	c.JSON(http.StatusOK, utils.AmisResponse{
		Msg: "服务器关机成功。",
	})
}

func ReBootServer(c *gin.Context) {
	query := OpServerInfo{}
	if err := c.ShouldBindJSON(&query); err != nil {
		utils.AmisError(c, "数据格式不正确，请修改后重新提交。")
		return
	}

	for _, serverId := range query.ServerIds {
		// 根据 server_id 获取主机信息，方便后续调用厂商接口重启
		serverDetail := models.GetServerDetail(serverId)
		vendorId := serverDetail.VendorId
		serverType := serverDetail.InstanceType
		instanceId := serverDetail.InstanceId
		projectId := serverDetail.ProjectId
		regionId := serverDetail.RegionId

		/* 主要逻辑：
		1. 根据 vendorId 和 serverType 做判断，调对应厂商的 API 重启，目前仅支持金山云(1)、Ucloud(2)
		2. 修改数据库中的记录状态为 Running */

		if vendorId == 1 {
			// 金山裸金属和虚拟机重启接口不同，要增加 serverType 判断
			if serverType == "vm" {
				if err := providers.KsyRebootVm(instanceId, regionId); err != nil {
					utils.AmisError(c, err)
					return
				}
			} else {
				if err := providers.KsyRebootBms(instanceId, regionId); err != nil {
					utils.AmisError(c, err)
					return
				}
			}
		} else if vendorId == 2 {
			if err := providers.UcloudRebootVm(instanceId, regionId, projectId); err != nil {
				utils.AmisError(c, err)
				return
			}
		} else {
			//TODO 补充其他厂商删除操作, 如 IDC 等
			utils.AmisError(c, "暂不支持该厂商重启操作。")
		}

		// 更新数据库记录
		if err := models.UpdateServerStatus(serverId, "Running"); err != nil {
			utils.AmisError(c, "update server status failed !")
			return
		}
	}

	c.JSON(http.StatusOK, utils.AmisResponse{
		Msg: "服务器重启成功。",
	})
}

func ReInstallServer(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"result": "ok!"})
}

func GetServerImageList(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"result": "ok!"})
}

func MaintenanceServer(c *gin.Context) {
	query := maintenanceInfo{}
	if err := c.ShouldBindJSON(&query); err != nil {
		utils.AmisError(c, "工单格式不正确，请修改后重新提交。")
		return
	}
	// 调金山 SDK 创建工单
	err := providers.KsyMaintenanceBms(
		query.Items[0].Zone, query.Title, query.Content,
		query.Items[0].InstanceId, query.Attribute, query.Confirm)
	if err != nil {
		utils.AmisError(c, err)
		return
	}

	c.JSON(http.StatusOK, utils.AmisResponse{
		Msg: "裸金属维修工单提交成功。",
	})
}
