package chart

import (
	"github.com/gin-gonic/gin"
	"hongze/hongze_yb/controller/response"
	"hongze/hongze_yb/models/response/my_chart"
	myChartModel "hongze/hongze_yb/models/tables/my_chart"
	"hongze/hongze_yb/models/tables/my_chart_classify"
	myChartClassifyMappingModel "hongze/hongze_yb/models/tables/my_chart_classify_mapping"
	myChartLogModel "hongze/hongze_yb/models/tables/my_chart_log"
	"hongze/hongze_yb/services/chart"
	"hongze/hongze_yb/services/user"
	"hongze/hongze_yb/utils"
	"io/ioutil"
	"strconv"
	"time"
)

// GetMyChartChassify 获取图表分类列表
// @Tags 图库模块
// @Summary  获取图表分类
// @Description 获取图表分类列表
// @Security ApiKeyAuth
// @Param Authorization	header string true "Bearer 31a165baebe6dec616b1f8f3207b4273"
// @Accept  json
// @Product json
// @Param Keywords query string false "分类名称关键词"
// @Success 200 {object} my_chart.MyChartClassifyListResp
// @failure 400 {string} string "分类列表获取失败"
// @Router /chart/getChartChassify [get]
func GetMyChartChassify(c *gin.Context) {
	userInfo := user.GetInfoByClaims(c)
	publicCondition := make(map[string]interface{})
	privateCondition := make(map[string]interface{})
	reqKeywords := c.DefaultQuery("Keywords", "")
	if reqKeywords != "" {
		publicCondition["my_chart_classify_name like"] = "%" + reqKeywords + "%"
		privateCondition["my_chart_classify_name like"] = "%" + reqKeywords + "%"
	}

	publicClassify, privateClassify, err := chart.GetUserChartClassifyListByCondition(userInfo, publicCondition, privateCondition)
	if err != nil {
		response.Fail("获取图表分类失败, Err:" + err.Error(), c)
		return
	}

	respData := &my_chart.MyChartClassifyListResp {
		PublicClassify: publicClassify,
		PrivateClassify: privateClassify,
	}
	response.OkData("获取成功", respData, c)
}

// GetMyChartList 获取图表列表
// @Tags 图库模块
// @Summary  获取图表列表
// @Description 获取图表列表
// @Security ApiKeyAuth
// @Param Authorization	header string true "Bearer 31a165baebe6dec616b1f8f3207b4273"
// @Accept  json
// @Product json
// @Param Keywords query string false "图表名称关键词"
// @Param ClassifyId query string false "图表分类ID"
// @Param Page query int false "当前页页码，从1开始"
// @Param Limit query int false "每页数据量"
// @Success 200 {object} []my_chart.MyChartList
// @failure 400 {string} string "图库列表获取失败"
// @Router /chart/getChartList [get]
func GetMyChartList(c *gin.Context) {
	userInfo := user.GetInfoByClaims(c)

	// 筛选
	var condition string
	var pars []interface{}
	reqKeywords := c.DefaultQuery("Keywords", "")
	reqClassifyId := c.DefaultQuery("ClassifyId", "")

	if reqClassifyId == "" && reqKeywords == "" {
		// 默认展示第一个最小分类下的图表
		publicCondition := make(map[string]interface{})
		privateCondition := make(map[string]interface{})
		publicClassify, privateClassify, err := chart.GetUserChartClassifyListByCondition(userInfo, publicCondition, privateCondition)
		if err != nil {
			response.FailMsg("获取失败", "获取图表分类信息失败, Err:" + err.Error(), c)
			return
		}
		// 内部员工默认取自己的第一个分类
		classifyId := 0
		if len(privateClassify) > 0 {
			classifyId = privateClassify[0].MyChartClassifyId
		} else {
			if len(publicClassify) > 0 {
				classifyId = publicClassify[0].MyChartClassifyId
			}
		}

		condition += " AND d.my_chart_classify_id = ?"
		pars = append(pars, classifyId)
	} else if reqKeywords != "" {
		// 关键词
		condition += " AND b.chart_name LIKE ?"
		pars = append(pars, "%" + reqKeywords + "%")
	} else {
		// 指定分类
		condition += " AND d.my_chart_classify_id = ?"
		pars = append(pars, reqClassifyId)
	}

	// 分页
	page, _ := strconv.Atoi(c.Query("Page"))
	limit, _ := strconv.Atoi(c.Query("Limit"))
	if page == 0 {
		page = 1
	}
	if limit == 0 {
		limit = 10
	}

	list, err := myChartModel.GetMyChartListByCondition(condition, pars, page, limit)
	if err != nil {
		response.FailMsg("获取失败", "获取图库列表失败, Err:" + err.Error(), c)
		return
	}

	response.OkData("获取成功", list, c)
}

// MoveMyChart 移动我的图表
// @Tags 图库模块
// @Summary  移动我的图表
// @Description 移动我的图表
// @Security ApiKeyAuth
// @Param Authorization	header string true "Bearer 31a165baebe6dec616b1f8f3207b4273"
// @Accept  json
// @Product json
// @Param data body myChartModel.MoveMyChartReq true "请求参数"
// @Success 200 {string} string "操作成功"
// @failure 400 {string} string "操作失败"
// @Router /my_chart/moveMyChart [post]
func MoveMyChart(c *gin.Context) {
	// 参数校验
	var req myChartModel.MoveMyChartReq
	if c.ShouldBind(&req) != nil {
		response.Fail("参数异常", c)
		return
	}
	if req.MyChartId == 0 {
		response.Fail("图表ID有误", c)
		return
	}
	if req.MyChartClassifyId == 0 {
		response.Fail("图表分类ID有误", c)
		return
	}

	// 操作权限校验
	userInfo := user.GetInfoByClaims(c)
	ok, adminInfo, err := user.GetAdminByUserInfo(userInfo)
	if err != nil {
		response.Fail("操作人信息有误", c)
		return
	}
	if !ok {
		response.Fail("非内部人员无权进行操作", c)
		return
	}
	adminId := int(adminInfo.AdminID)
	myChassify, err := my_chart_classify.GetClassifyById(req.MyChartClassifyId)
	if err != nil {
		if err == utils.ErrNoRow {
			response.FailMsg("操作失败", "图表分类信息有误, Err:" + err.Error(), c)
			return
		}
		response.FailMsg("操作失败", "获取图表分类信息失败, Err:" + err.Error(), c)
		return
	}
	if myChassify.AdminID != adminId {
		response.Fail("无权移动该图表", c)
		return
	}

	// 图表排序
	step := float64(65536)
	var newSort float64
	if req.PrevMyChartId <= 0 {
		firstMapItem, err := myChartClassifyMappingModel.GetMyChartSort(adminId, req.MyChartClassifyId, 0)
		if err != nil {
			response.FailMsg("操作失败", "获取图表排序失败4001, Err:" + err.Error(), c)
			return
		}
		if firstMapItem.Sort <= 0 {
			firstSort := step / float64(2)
			err = myChartClassifyMappingModel.MyChartMove(firstSort, adminId, firstMapItem.MyChartId, firstMapItem.MyChartClassifyId)
			if err != nil {
				response.FailMsg("操作失败", "移动失败4001, Err:" + err.Error(), c)
				return
			}
			newSort = step / float64(4)
		} else {
			newSort = firstMapItem.Sort / float64(2)
		}
	} else if req.NextMyChartId <= 0 {
		latestMapItem, err := myChartClassifyMappingModel.GetMyChartSort(adminId, req.MyChartClassifyId, 1)
		if err != nil {
			response.FailMsg("操作失败", "获取图表排序失败4002, Err:" + err.Error(), c)
			return
		}
		if latestMapItem.Sort <= 0 {
			latestSort := step / float64(2)
			err = myChartClassifyMappingModel.MyChartMove(latestSort, adminId, latestMapItem.MyChartId, latestMapItem.MyChartClassifyId)
			if err != nil {
				response.FailMsg("操作失败", "移动失败4002, Err:" + err.Error(), c)
				return
			}
			newSort = step / float64(4)
		} else {
			newSort = latestMapItem.Sort + (step / float64(2)) - 1
		}
	} else {
		preMapItem, err := myChartClassifyMappingModel.GetMyChartClassifyMapping(adminId, req.PrevMyChartId, req.MyChartClassifyId)
		if err != nil {
			response.FailMsg("操作失败", "获取上级图表关联信息失败, Err:" + err.Error(), c)
			return
		}
		nextMapItem, err := myChartClassifyMappingModel.GetMyChartClassifyMapping(adminId, req.NextMyChartId, req.MyChartClassifyId)
		if err != nil {
			response.FailMsg("操作失败", "获取下级图表关联信息失败, Err:" + err.Error(), c)
			return
		}
		newSort = (preMapItem.Sort + nextMapItem.Sort) / 2
	}
	if newSort >= 0 {
		err = myChartClassifyMappingModel.MyChartMove(newSort, adminId, req.MyChartId, req.MyChartClassifyId)
		if err != nil {
			response.FailMsg("操作失败", "移动失败4003, Err:" + err.Error(), c)
			return
		}
	}

	// 新增操作日志
	{
		bodyBytes, _ := ioutil.ReadAll(c.Request.Body)
		requestBodyStr := string(bodyBytes)

		edbLog := new(myChartLogModel.MyChartLog)
		edbLog.MyChartId = 0
		edbLog.ChartInfoId = 0
		edbLog.SysUserId = adminId
		edbLog.SysUserRealName = adminInfo.RealName
		edbLog.CreateTime = time.Now()
		edbLog.Content = requestBodyStr
		edbLog.Status = "移动我的图表"
		edbLog.Method = c.Request.URL.String()
		go edbLog.Create()
	}

	response.Ok("操作成功", c)
}

// MoveMyChart 移动我的图表分类
// @Tags 图库模块
// @Summary  移动我的图表分类
// @Description 移动我的图表分类
// @Security ApiKeyAuth
// @Param Authorization	header string true "Bearer 31a165baebe6dec616b1f8f3207b4273"
// @Accept  json
// @Product json
// @Param data body myChartModel.MoveMyChartClassifyReq true "请求参数"
// @Success 200 {string} string "操作成功"
// @failure 400 {string} string "操作失败"
// @Router /my_chart/moveMyChartClassify [post]
func MoveMyChartClassify(c *gin.Context) {
	// 参数校验
	var req myChartModel.MoveMyChartClassifyReq
	if c.ShouldBind(&req) != nil {
		response.Fail("参数异常", c)
		return
	}
	if req.MyChartClassifyId == 0 {
		response.Fail("图表分类ID有误", c)
		return
	}

	// 操作权限校验
	userInfo := user.GetInfoByClaims(c)
	ok, adminInfo, err := user.GetAdminByUserInfo(userInfo)
	if err != nil {
		response.Fail("操作人信息有误", c)
		return
	}
	if !ok {
		response.Fail("非内部人员无权进行操作", c)
		return
	}
	adminId := int(adminInfo.AdminID)
	myChassify, err := my_chart_classify.GetClassifyById(req.MyChartClassifyId)
	if err != nil {
		if err == utils.ErrNoRow {
			response.FailMsg("操作失败", "该图表分类信息有误, Err:", c)
			return
		}
		response.FailMsg("操作失败", "获取图表信息失败" + err.Error(), c)
		return
	}
	if myChassify.AdminID != adminId {
		response.Fail("无权移动该图表", c)
		return
	}

	// 移动分类
	updateCol := make([]string, 0)
	if req.PrevClassifyId > 0 {
		prevClassify, err := my_chart_classify.GetClassifyByIdAndAdminId(adminId, req.PrevClassifyId)
		if err != nil {
			response.FailMsg("操作失败", "移动失败, 获取上一个兄弟节点分类信息失败, Err:" + err.Error(), c)
			return
		}

		// 如果是移动在两个兄弟节点之间
		if req.NextClassifyId > 0 {
			// 下一个兄弟节点
			nextClassify, err := my_chart_classify.GetClassifyByIdAndAdminId(adminId, req.NextClassifyId)
			if err != nil {
				response.FailMsg("操作失败", "移动失败, 获取下一个兄弟节点分类信息失败, Err:" + err.Error(), c)
				return
			}
			// 如果上一个兄弟与下一个兄弟的排序权重是一致的，那么需要将下一个兄弟（以及下个兄弟的同样排序权重）的排序权重+2，自己变成上一个兄弟的排序权重+1
			if prevClassify.Sort == nextClassify.Sort || prevClassify.Sort == myChassify.Sort {
				// 变更兄弟节点的排序
				updateSortStr := `sort + 2`
				_ = my_chart_classify.UpdateMyChartClassifySortByClassifyId(adminId, prevClassify.MyChartClassifyId, prevClassify.Sort, updateSortStr)
			} else {
				// 如果下一个兄弟的排序权重正好是上个兄弟节点的下一层，那么需要再加一层了
				if nextClassify.Sort-prevClassify.Sort == 1 {
					// 变更兄弟节点的排序
					updateSortStr := `sort + 1`
					_ = my_chart_classify.UpdateMyChartClassifySortByClassifyId(adminId, 0, prevClassify.Sort, updateSortStr)
				}
			}
		}

		myChassify.Sort = prevClassify.Sort + 1
		myChassify.ModifyTime = time.Now()
		updateCol = append(updateCol, "Sort", "ModifyTime")
	} else {
		firstClassify, err := my_chart_classify.GetFirstClassifyByAdminId(adminId)
		if err != nil && err != utils.ErrNoRow {
			response.FailMsg("操作失败", "移动失败, 获取获取当前账号下的排序第一条的分类信息失败, Err:" + err.Error(), c)
			return
		}

		//如果该分类下存在其他分类，且第一个其他分类的排序等于0，那么需要调整排序
		if firstClassify != nil && firstClassify.Sort == 0 {
			updateSortStr := ` sort + 1 `
			_ = my_chart_classify.UpdateMyChartClassifySortByClassifyId(adminId, firstClassify.MyChartClassifyId-1, 0, updateSortStr)
		}

		myChassify.Sort = 0 //那就是排在第一位
		myChassify.ModifyTime = time.Now()
		updateCol = append(updateCol, "Sort", "ModifyTime")
	}

	// 更新
	if len(updateCol) > 0 {
		err = my_chart_classify.UpdateClassifySort(adminId, myChassify.MyChartClassifyId, myChassify.Sort, myChassify.ModifyTime)
		if err != nil {
			response.FailMsg("操作失败", "更新图表分类排序失败, Err:" + err.Error(), c)
			return
		}
	}

	//新增操作日志
	{
		bodyBytes, _ := ioutil.ReadAll(c.Request.Body)
		requestBodyStr := string(bodyBytes)

		edbLog := new(myChartLogModel.MyChartLog)
		edbLog.MyChartId = 0
		edbLog.ChartInfoId = 0
		edbLog.SysUserId = adminId
		edbLog.SysUserRealName = adminInfo.RealName
		edbLog.CreateTime = time.Now()
		edbLog.Content = requestBodyStr
		edbLog.Status = "移动分类"
		edbLog.Method = c.Request.URL.String()
		go edbLog.Create()
	}

	response.Ok("操作成功", c)
}