package chart

import (
	"github.com/gin-gonic/gin"
	"hongze/hongze_yb/controller/response"
	"hongze/hongze_yb/models/response/my_chart"
	chartInfoModel "hongze/hongze_yb/models/tables/chart_info"
	"hongze/hongze_yb/models/tables/edb_info_no_permission_admin"
	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", "")

	// 获取用户图表分类权限
	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
	}

	if reqClassifyId == "" && reqKeywords == "" {
		// 内部员工默认取自己的第一个分类
		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+"%")
		// 搜索自己权限内的图表
		classifyIds := make([]int, 0)
		for i := 0; i < len(publicClassify); i++ {
			classifyIds = append(classifyIds, publicClassify[i].MyChartClassifyId)
		}
		for i := 0; i < len(privateClassify); i++ {
			classifyIds = append(classifyIds, privateClassify[i].MyChartClassifyId)
		}
		condition += " AND d.my_chart_classify_id IN (?)"
		pars = append(pars, classifyIds)
	} else {
		// 指定分类
		condition += " AND d.my_chart_classify_id = ?"
		pars = append(pars, reqClassifyId)
	}

	// 获取当前账号的不可见指标
	noPermissionChartIdList := make([]int, 0)
	{
		ok, adminInfo, err := user.GetAdminByUserInfo(userInfo)
		if err != nil {
			response.Fail("操作人信息有误", c)
			return
		}
		if !ok {
			response.Fail("非内部人员无权进行操作", c)
			return
		}
		confList, err := edb_info_no_permission_admin.GetAllChartListByAdminId(int(adminInfo.AdminID))
		if err != nil {
			response.FailMsg("获取失败", "获取不可见指标配置数据失败, Err:"+err.Error(), c)
			return
		}
		for _, v := range confList {
			noPermissionChartIdList = append(noPermissionChartIdList, v.ChartInfoId)
		}
	}

	lenNoPermissionChartIdList := len(noPermissionChartIdList)
	if lenNoPermissionChartIdList > 0 {
		condition += ` AND b.chart_info_id not in (?) `
		pars = append(pars, noPermissionChartIdList)
	}

	// 分页
	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)
}

// GetChartBeforeAndNext 获取当前图表上一张及下一张信息
// @Tags 图库模块
// @Summary  获取当前图表上一张及下一张信息
// @Description 获取当前图表上一张及下一张信息
// @Security ApiKeyAuth
// @Param Authorization	header string true "Bearer 31a165baebe6dec616b1f8f3207b4273"
// @Accept  json
// @Product json
// @Param MyChartId query string false "我的图表ID"
// @Param MyChartClassifyId query string false "我的图表分类ID"
// @Success 200 {object} chartInfoModel.ChartBeforeNext
// @failure 400 {string} string "获取失败"
// @Router /my_chart/getChartBeforeAndNext [get]
func GetChartBeforeAndNext(c *gin.Context) {
	// 参数校验
	reqMyChartId := c.DefaultQuery("MyChartId", "")
	if reqMyChartId == "" {
		response.Fail("参数有误:图表ID", c)
		return
	}
	myChartId, _ := strconv.Atoi(reqMyChartId)
	myChartClassifyId := c.DefaultQuery("MyChartClassifyId", "")
	if myChartClassifyId == "" {
		response.Fail("参数有误:图表分类ID", c)
		return
	}

	// 当前图表
	myChartInfo, err := myChartModel.GetMyChartById(myChartId, myChartClassifyId)
	if err != nil {
		if err == utils.ErrNoRow {
			response.Fail("图表已被删除，请刷新当前页面", c)
			return
		}
		response.FailMsg("获取失败", "获取我的图表信息失败, Err:"+err.Error(), c)
		return
	}

	// 获取当前图表所在分类的所有图表信息
	myChartList, err := myChartClassifyMappingModel.GetMyChartSortInfoList(myChartClassifyId, 2)
	// 找出当前图表前一张及后一张，当前图为最前一张或最后一张时需要取其他分类的图
	var currentIndex int
	lastIndex := len(myChartList) - 1
	for index, item := range myChartList {
		if myChartInfo.MyChartId == item.MyChartId {
			currentIndex = index
			break
		}
	}
	var beforeChart, afterChart *myChartClassifyMappingModel.MyChartSortInfo
	beforeIndex := currentIndex - 1
	if beforeIndex >= 0 {
		// 存在同分类上一张
		beforeChart = myChartList[beforeIndex]
	}
	afterIndex := currentIndex + 1
	if afterIndex <= lastIndex {
		// 存在同分类下一张
		afterChart = myChartList[afterIndex]
	}
	// 检索其他分类
	if beforeIndex < 0 || afterIndex > lastIndex {
		// 获取当前用户有权限查看的图表分类
		userInfo := user.GetInfoByClaims(c)
		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
		}
		// 合并公共及私有分类
		var classifyList []*my_chart_classify.MyChartClassify
		for i := 0; i < len(publicClassify); i++ {
			classifyList = append(classifyList, publicClassify[i])
		}
		for i := 0; i < len(privateClassify); i++ {
			classifyList = append(classifyList, privateClassify[i])
		}
		// 获取当前图表分类在所有分类中的位置
		var currentClassifyIndex int
		for indexClassify, itemClassify := range classifyList {
			itemClassifyId := strconv.Itoa(itemClassify.MyChartClassifyId)
			if myChartClassifyId == itemClassifyId {
				currentClassifyIndex = indexClassify
				break
			}
		}
		lastClassifyIndex := len(classifyList) - 1

		// 若图表为分类第一张，则取上一个分类最后一张作为上一张返回
		beforeClassifyIndex := currentClassifyIndex - 1
		if beforeIndex < 0 && len(classifyList) > 0 && beforeClassifyIndex >= 0 {
			beforeClassifyIdStr := strconv.Itoa(classifyList[beforeClassifyIndex].MyChartClassifyId)
			beforeClassifyChartList, tempErr := myChartClassifyMappingModel.GetMyChartSortInfoList(beforeClassifyIdStr, 1)
			if tempErr != nil {
				response.FailMsg("获取失败", "获取上一个分类图表信息失败4101, Err:"+tempErr.Error(), c)
				return
			}
			// 上一个分类没有图则继续向上取最后一张直到所取的分类为第一个分类，依旧无图则到顶
		SearchPrevChart:
			if len(beforeClassifyChartList) > 0 {
				beforeChart = beforeClassifyChartList[0]
			} else {
				beforeClassifyIndex -= 1
				if beforeClassifyIndex >= 0 {
					beforeClassifyIdStr = strconv.Itoa(classifyList[beforeClassifyIndex].MyChartClassifyId)
					beforeClassifyChartList, tempErr = myChartClassifyMappingModel.GetMyChartSortInfoList(beforeClassifyIdStr, 1)
					if tempErr != nil {
						response.FailMsg("获取失败", "获取上一个分类图表信息失败4102, Err:"+tempErr.Error(), c)
						return
					}
					goto SearchPrevChart
				}
			}
		}
		// 若图表为分类最后一张，则取下一个分类第一张作为下一张返回
		afterClassifyIndex := currentClassifyIndex + 1
		if afterIndex > lastIndex && len(classifyList) > 0 && afterClassifyIndex <= lastClassifyIndex {
			afterClassifyIdStr := strconv.Itoa(classifyList[afterClassifyIndex].MyChartClassifyId)
			afterClassifyChartList, tempErr := myChartClassifyMappingModel.GetMyChartSortInfoList(afterClassifyIdStr, 2)
			if tempErr != nil {
				response.FailMsg("获取失败", "获取下一个分类图表信息失败4103, Err:"+tempErr.Error(), c)
				return
			}
			// 下一个分类没有图则继续向下取第一张直到所取的分类为最后一个分类，依旧无图则到底
		SearchNextChart:
			if len(afterClassifyChartList) > 0 {
				afterChart = afterClassifyChartList[0]
			} else {
				afterClassifyIndex += 1
				if afterClassifyIndex <= lastClassifyIndex {
					afterClassifyIdStr = strconv.Itoa(classifyList[afterClassifyIndex].MyChartClassifyId)
					afterClassifyChartList, tempErr = myChartClassifyMappingModel.GetMyChartSortInfoList(afterClassifyIdStr, 2)
					if tempErr != nil {
						response.FailMsg("获取失败", "获取下一个分类图表信息失败4104, Err:"+tempErr.Error(), c)
						return
					}
					goto SearchNextChart
				}
			}
		}
	}

	var beforeResp, afterResp chartInfoModel.ChartSortInfo
	if beforeChart != nil {
		beforeResp.MyChartId = beforeChart.MyChartId
		beforeResp.MyChartClassifyId = beforeChart.MyChartClassifyId
		beforeResp.MyChartClassifyName = beforeChart.MyChartClassifyName
		beforeResp.Sort = int(beforeChart.Sort)
		beforeResp.UniqueCode = beforeChart.UniqueCode
		beforeResp.ChartInfoId = beforeChart.ChartInfoId
		beforeResp.ChartInfoSource = beforeChart.ChartInfoSource
		if beforeIndex < 0 {
			beforeResp.Switch = 1
		}
	}
	if afterChart != nil {
		afterResp.MyChartId = afterChart.MyChartId
		afterResp.MyChartClassifyId = afterChart.MyChartClassifyId
		afterResp.MyChartClassifyName = afterChart.MyChartClassifyName
		afterResp.Sort = int(afterChart.Sort)
		afterResp.UniqueCode = afterChart.UniqueCode
		afterResp.ChartInfoId = afterChart.ChartInfoId
		afterResp.ChartInfoSource = afterChart.ChartInfoSource
		if afterIndex > lastIndex {
			afterResp.Switch = 1
		}
	}
	resp := chartInfoModel.ChartBeforeNext{
		PrevChart: beforeResp,
		NextChart: afterResp,
	}

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