package knowledge

import (
	"errors"
	"eta_gn/eta_api/models/knowledge"
	"eta_gn/eta_api/services/alarm_msg"
	"eta_gn/eta_api/utils"
	"fmt"
	"sort"
	"time"
)

// MoveKnowledgeClassify 移动分类
func MoveKnowledgeClassify(req knowledge.ClassifyMoveReq) (err error, errMsg string) {
	knowledgeObj := new(knowledge.KnowledgeClassify)
	classifyId := req.ClassifyId
	prevClassifyId := req.PrevClassifyId
	nextClassifyId := req.NextClassifyId

	//如果有传入 上一个兄弟节点分类id
	var (
		classifyInfo *knowledge.KnowledgeClassify
		prevClassify *knowledge.KnowledgeClassify
		nextClassify *knowledge.KnowledgeClassify

		prevSort int
		nextSort int
	)

	// 移动对象为分类, 判断权限
	classifyInfo, err = knowledgeObj.GetClassifyById(classifyId)
	if err != nil {
		if utils.IsErrNoRow(err) {
			errMsg = "分类不存在, 请刷新页面"
			err = fmt.Errorf("获取分类信息失败,Err:" + err.Error())
			return
		}
		errMsg = "移动失败"
		err = fmt.Errorf("获取分类信息失败,Err:" + err.Error())
		return
	} else if classifyInfo.ClassifyId == 0 {
		errMsg = "分类不存在, 请刷新页面"
		err = fmt.Errorf("获取分类信息失败")
		return
	}

	parentClassifyId := classifyInfo.ParentId
	if prevClassifyId > 0 {
		prevClassify, err = knowledgeObj.GetClassifyById(prevClassifyId)
		if err != nil {
			if utils.IsErrNoRow(err) {
				errMsg = "上一个分类不存在, 请刷新页面"
				err = fmt.Errorf("获取分类信息失败,Err:" + err.Error())
				return
			}
			errMsg = "移动失败"
			err = fmt.Errorf("获取上一个兄弟节点分类信息失败,Err:" + err.Error())
			return
		}
		if prevClassify.ParentId != parentClassifyId {
			errMsg = "禁止拖动到其他节点"
			err = fmt.Errorf(errMsg)
			return
		}
		prevSort = prevClassify.Sort
	}

	if nextClassifyId > 0 {
		//下一个兄弟节点
		nextClassify, err = knowledgeObj.GetClassifyById(nextClassifyId)
		if err != nil {
			if utils.IsErrNoRow(err) {
				errMsg = "下一个分类不存在, 请刷新页面"
				err = fmt.Errorf("获取分类信息失败,Err:" + err.Error())
				return
			}
			errMsg = "移动失败"
			err = fmt.Errorf("获取下一个兄弟节点分类信息失败,Err:" + err.Error())
			return
		}
		if nextClassify.ParentId != parentClassifyId {
			errMsg = "禁止拖动到其他节点"
			err = fmt.Errorf(errMsg)
			return
		}
		nextSort = nextClassify.Sort
	}

	err, errMsg = moveKnowledgeClassify(classifyInfo, prevClassify, nextClassify, parentClassifyId, prevSort, nextSort, classifyInfo.ResourceType)
	return
}

// moveKnowledgeClassify 移动分类
func moveKnowledgeClassify(classifyInfo, prevClassify, nextClassify *knowledge.KnowledgeClassify, parentId, prevSort, nextSort, resourceType int) (err error, errMsg string) {
	knowledgeObj := new(knowledge.KnowledgeClassify)
	updateCol := make([]string, 0)

	//判断上级id是否一致,如果不一致的话,那么需要移动该分类层级
	if classifyInfo.ParentId != parentId {
		errMsg = "移动失败"
		err = fmt.Errorf("不支持目录层级变更")
		return
	}

	if prevSort > 0 {
		//如果是移动在两个兄弟节点之间
		if nextSort > 0 {
			//下一个兄弟节点
			//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
			if prevSort == nextSort || prevSort == classifyInfo.Sort {
				//变更兄弟节点的排序
				updateSortStr := `sort + 2`

				//变更分类
				if prevClassify != nil {
					_ = knowledgeObj.UpdateClassifySortByParentId(parentId, prevClassify.ClassifyId, prevClassify.Sort, updateSortStr, resourceType)
				} else {
					_ = knowledgeObj.UpdateClassifySortByParentId(parentId, 0, prevSort, updateSortStr, resourceType)
				}

			} else {
				//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
				if nextSort-prevSort == 1 {
					//变更兄弟节点的排序
					updateSortStr := `sort + 1`

					//变更分类
					if prevClassify != nil {
						_ = knowledgeObj.UpdateClassifySortByParentId(parentId, prevClassify.ClassifyId, prevSort, updateSortStr, resourceType)
					} else {
						_ = knowledgeObj.UpdateClassifySortByParentId(parentId, 0, prevSort, updateSortStr, resourceType)
					}

				}
			}
		}

		classifyInfo.Sort = prevSort + 1
		classifyInfo.ModifyTime = time.Now()
		updateCol = append(updateCol, "Sort", "ModifyTime")
	} else if prevClassify == nil && nextClassify == nil && parentId > 0 {
		//处理只拖动到目录里,默认放到目录底部的情况
		var maxSort int
		maxSort, err = knowledgeObj.GetMaxSortByParentId(parentId)
		if err != nil {
			errMsg = "移动失败"
			err = fmt.Errorf("查询组内排序信息失败,Err:" + err.Error())
			return
		}
		classifyInfo.Sort = maxSort + 1 //那就是排在组内最后一位
		classifyInfo.ModifyTime = time.Now()
		updateCol = append(updateCol, "Sort", "ModifyTime")
	} else {
		// 拖动到父级分类的第一位
		firstPermission, tmpErr := knowledgeObj.GetFirstClassifyByParentId(parentId)
		if tmpErr != nil && !utils.IsErrNoRow(tmpErr) {
			errMsg = "移动失败"
			err = fmt.Errorf("获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + tmpErr.Error())
			return
		}

		//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
		if firstPermission != nil && firstPermission.ClassifyId != 0 && firstPermission.Sort == 0 {
			updateSortStr := ` sort + 1 `
			_ = knowledgeObj.UpdateClassifySortByParentId(parentId, firstPermission.ClassifyId-1, 0, updateSortStr, resourceType)
		}

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

	//更新
	if len(updateCol) > 0 {
		err = classifyInfo.Update(updateCol)
		if err != nil {
			errMsg = "移动失败"
			err = fmt.Errorf("修改失败,Err:" + err.Error())
			return
		}
	}
	return
}

// AddKnowledgeClassify
// @Description: 添加报告分类
// @author: Roc
// @datetime 2024-06-17 11:01:21
// @param classifyName string
// @param parentId int
// @param chartPermissionIdList []int
// @return err error
// @return errMsg string
// @return isSendEmail bool
func AddKnowledgeClassify(classifyName string, parentId, resourceType int) (err error, errMsg string, isSendEmail bool) {
	isSendEmail = true
	errMsg = `添加失败`
	knowledgeObj := new(knowledge.KnowledgeClassify)
	_, err = knowledgeObj.GetClassifyByName(classifyName, parentId, resourceType)
	if err != nil && !utils.IsErrNoRow(err) {
		errMsg = "获取分类信息失败"
		return
	}

	if err == nil {
		errMsg = "分类名称:" + classifyName + "已存在"
		isSendEmail = false
		err = errors.New(errMsg)
		return
	} else {
		err = nil
	}

	level := 1
	// 父级分类
	var parentClassifyItem *knowledge.KnowledgeClassify
	// 父级分类下的子分类数量
	var childClassifyCount int

	if parentId > 0 {
		// 获取父级分类信息
		parentClassifyItem, err = knowledgeObj.GetClassifyById(parentId)
		if err != nil {
			errMsg = "获取父级分类信息失败"
			if utils.IsErrNoRow(err) {
				errMsg = "父级分类不存在"
			}
			return
		}
		if parentClassifyItem.ResourceType != resourceType {
			errMsg = "父级分类与当前分类类型不一致"
			err = fmt.Errorf(errMsg)
			return
		}
		level = parentClassifyItem.Level + 1

		if level > 3 {
			errMsg = "分类层级不可超过三级"
			isSendEmail = false
			return
		}
		// 获取父级分类下的子分类数量
		childClassifyCount, err = knowledgeObj.GetCountClassifyChildByParentId(parentId)
		if err != nil {
			errMsg = "获取父级分类的子分类信息失败"
			return
		}
	}

	nowTime := time.Now().Local()
	classify := new(knowledge.KnowledgeClassify)

	maxSort, err := classify.GetMaxSort()
	if err != nil {
		errMsg = "操作失败"
		err = errors.New("查询品种排序失败, Err: " + err.Error())
		return
	}
	classify.ClassifyName = classifyName
	classify.ParentId = parentId
	classify.CreateTime = nowTime
	classify.ModifyTime = nowTime
	classify.Sort = maxSort + 1
	classify.Enabled = 1
	classify.Level = level
	classify.ResourceType = resourceType

	err = knowledgeObj.Add(classify)
	if err != nil {
		return
	}
	fmt.Println("classify.ClassifyId:")
	fmt.Println(classify.ClassifyId)
	// 如果父级分类不为空的话,那么就标记有子级分类,同时
	if parentClassifyItem != nil {
		/*parentClassifyItem.HasChild = 1
		err = parentClassifyItem.Update([]string{"HasChild"})
		if err != nil {
			return
		}
		*/
		// 如果以前没有子级分类,那么就继承父级分类下的章节类型(创建新的章节与分类的关系)
		if childClassifyCount <= 0 {
			moveResourceByAddClassify(parentClassifyItem, classify, resourceType)
		}
	}
	return
}

// 关于研报分类,因只允许报告或品种关联在最小分类下,所以当某个父分类(非三级分类)已关联报告或品种,需要在该父分类下增加子分类,则第一个子分类添加成功时,默认把该父分类关联的品种和报告转移至新创建的子分类(第一个子分类)下
// moveReportByAddClassify
// @Description: 报告和章节的转移
// @author: Roc
// @datetime 2024-06-17 16:29:56
// @param parentClassifyInfo *knowledge.KnowledgeClassify
// @param currClassifyInfo *knowledge.KnowledgeClassify
// @return err error
func moveResourceByAddClassify(parentClassifyInfo, currClassifyInfo *knowledge.KnowledgeClassify, resourceType int) (err error) {
	defer func() {
		if err != nil {
			msg := fmt.Sprint("历史事件更改分类失败,父级分类ID:", parentClassifyInfo.ClassifyId, ";当前分类ID:", currClassifyInfo.ClassifyId, ";错误信息:", err.Error())
			utils.FileLog.Error(msg)
			go alarm_msg.SendAlarmMsg(msg, 3)
		}
	}()
	if currClassifyInfo.Level > 3 {
		err = errors.New("父级分类不支持三级分类以上")
		return
	}

	// 报告的分类归属调整,转为下一级的分类
	var condition string
	pars := make([]interface{}, 0)
	condition += ` AND resource_type = ? `
	pars = append(pars, resourceType)
	// 查询是需要转移的资源数量
	condition += ` AND classify_id = ? `
	pars = append(pars, parentClassifyInfo.ClassifyId)
	idList, err := knowledge.GetKnowledgeResourceIdList(condition, pars)
	if err != nil {
		err = fmt.Errorf("查询需要转移的资源数量失败,Err: %s", err.Error())
		return
	}
	if len(idList) == 0 { //没有需要转移的资源
		return
	}

	newClassifyId := currClassifyInfo.ClassifyId
	if currClassifyInfo.Level == 2 {
		//查询排名第一的子分类
		classifyObj := new(knowledge.KnowledgeClassify)
		childClassify, e := classifyObj.GetFirstClassifyByParentId(currClassifyInfo.ClassifyId)
		if e == nil {
			newClassifyId = childClassify.ClassifyId
		}
	}
	resourceObj := new(knowledge.KnowledgeResource)
	// 批量事件的分类ID
	err = resourceObj.UpdateClassifyIdByIds(idList, newClassifyId, resourceType)
	return
}

func EditKnowledgeClassify(classifyId, parentId int, classifyName string, resourceType int) (err error, errMsg string, isSendEmail bool) {
	isSendEmail = true
	errMsg = `修改失败`
	knowledgeObj := new(knowledge.KnowledgeClassify)
	item, err := knowledgeObj.GetClassifyById(classifyId)
	if err != nil {
		errMsg = "获取分类信息失败"
		if utils.IsErrNoRow(err) {
			errMsg = "分类不存在, 或已被删除"
			isSendEmail = false
		}
		return
	}
	if item.ResourceType != resourceType {
		errMsg = "分类类型错误"
		err = errors.New("分类类型错误")
		return
	}

	if (parentId == 0 && item.ParentId > 0) || (parentId > 0 && item.ParentId == 0) {
		err = errors.New("不允许修改分类层级")
		errMsg = "不允许修改分类层级"
		return
	}
	// 父级分类
	var parentClassifyItem *knowledge.KnowledgeClassify
	// 父级分类下的子分类数量
	var childClassifyCount int

	if parentId > 0 {
		// 获取父级分类信息
		parentClassifyItem, err = knowledgeObj.GetClassifyById(parentId)
		if err != nil {
			errMsg = "获取父级分类信息失败"
			if utils.IsErrNoRow(err) {
				errMsg = "父级分类不存在"
			}
			return
		}
		if parentClassifyItem.ResourceType != resourceType {
			errMsg = "父级分类与当前分类类型不一致"
			err = fmt.Errorf(errMsg)
			return
		}
		if parentClassifyItem.Level+1 != item.Level {
			errMsg = "不允许修改分类层级"
			err = errors.New("不允许修改分类层级")
			return
		}
		level := parentClassifyItem.Level + 1

		if level > 3 {
			errMsg = "分类层级不可超过三级"
			isSendEmail = false
			return
		}
		// 获取父级分类下的子分类数量
		childClassifyCount, err = knowledgeObj.GetCountClassifyChildByParentId(parentId)
		if err != nil {
			errMsg = "获取父级分类的子分类信息失败"
			return
		}
	}

	//originName := item.ClassifyName

	// 重名校验
	existName, e := knowledgeObj.GetClassifyByName(classifyName, parentId, item.ResourceType)
	if e != nil && !utils.IsErrNoRow(e) {
		errMsg = "分类名称已存在"
		err = errors.New("获取重名分类失败, Err: " + e.Error())
		return
	}
	if existName != nil && existName.ClassifyId > 0 && existName.ClassifyId != item.ClassifyId {
		errMsg = "分类名称:" + classifyName + "已存在"
		err = errors.New(errMsg)
		isSendEmail = false
		return
	}
	item.ClassifyName = classifyName

	item.ParentId = parentId
	item.ModifyTime = time.Now().Local()
	cols := make([]string, 0)
	cols = append(cols, "ParentId", "ClassifyName", "ModifyTime")
	err = item.Update(cols)
	if err != nil {
		return
	}
	// 修改父级分类下相关的事件,找到当前分类的最小分类,把上一级的报告挪到最小分类上
	// 如果父级分类不为空的话,那么就标记有子级分类,同时
	if parentClassifyItem != nil {
		/*parentClassifyItem.HasChild = 1
		err = parentClassifyItem.Update([]string{"HasChild"})
		if err != nil {
			return
		}*/

		// 如果以前没有子级分类,那么就继承父级分类下的章节类型(创建新的章节与分类的关系)
		if childClassifyCount <= 0 {
			moveResourceByAddClassify(parentClassifyItem, item, resourceType)
		}
	}
	return
}

// GetClassifyTreeRecursive 递归获取分类树形结构
func GetClassifyTreeRecursive(list []*knowledge.KnowledgeClassifyItem, parentId int) []*knowledge.KnowledgeClassifyItem {
	res := make([]*knowledge.KnowledgeClassifyItem, 0)
	for _, v := range list {
		if v.ParentId == parentId {
			v.Child = GetClassifyTreeRecursive(list, v.ClassifyId)
			res = append(res, v)
		}
	}
	return res
}

// GetParentClassifyListByParentIdList
// @Description: 递归获取父级分类信息,正常来讲只有三次
// @author: Roc
// @datetime 2024-06-19 13:23:33
// @param parentClassifyIdList []int
// @return list []*knowledge.KnowledgeClassifyItem
// @return err error
func GetParentClassifyListByParentIdList(parentClassifyIdList []int) (list []*knowledge.KnowledgeClassifyItem, err error) {
	knowledgeObj := new(knowledge.KnowledgeClassify)
	num := len(parentClassifyIdList)
	if num <= 0 {
		return
	}
	list, err = knowledgeObj.GetClassifyListByParentIdList(parentClassifyIdList)
	if err != nil {
		return
	}

	// 是否还有上级
	{
		currParentClassifyIdList := make([]int, 0)
		for _, v := range list {
			if v.ParentId > 0 {
				currParentClassifyIdList = append(currParentClassifyIdList, v.ParentId)
			}
		}

		if len(currParentClassifyIdList) > 0 {
			tmpList, tmpErr := GetParentClassifyListByParentIdList(currParentClassifyIdList)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			list = append(tmpList, list...)
		}
	}

	return
}

// GetClassifyListTreeRecursive
// @Description: 递归获取分类树形结构
// @author: Roc
// @datetime 2024-06-19 13:23:28
// @param list []*knowledge.KnowledgeClassifyItem
// @param parentId int
// @return []*knowledge.KnowledgeClassifyItem
func GetClassifyListTreeRecursive(list []*knowledge.KnowledgeClassifyItem, parentId int) []*knowledge.KnowledgeClassifyItem {
	res := make([]*knowledge.KnowledgeClassifyItem, 0)
	for _, v := range list {
		if v.ParentId == parentId {
			v.Child = GetClassifyListTreeRecursive(list, v.ClassifyId)
			res = append(res, v)
		}
	}

	// 前端的JP需要我这么返回
	if len(res) <= 0 {
		res = nil
	}

	return res
}

// BySortAndCreateTime 用来排序,先按Sort字段升序排序,若Sort相同,则按照CreateTime字段升序排序。
type BySortAndCreateTime []*knowledge.KnowledgeClassifyItem

func (a BySortAndCreateTime) Len() int {
	return len(a)
}

func (a BySortAndCreateTime) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a BySortAndCreateTime) Less(i, j int) bool {
	if a[i].Sort == a[j].Sort {
		return a[i].CreateTime.Before(a[j].CreateTime)
	}
	return a[i].Sort < a[j].Sort
}

// SortClassifyListBySortAndCreateTime sorts the ClassifyList slice by Sort and then CreateTime in ascending order.
func SortClassifyListBySortAndCreateTime(classifyList []*knowledge.KnowledgeClassifyItem) {
	sort.Sort(BySortAndCreateTime(classifyList))
}