package materialService

import (
	"eta/eta_api/models"
	"eta/eta_api/models/data_manage"
	"eta/eta_api/models/data_manage/excel"
	"eta/eta_api/models/material"
	"eta/eta_api/models/sandbox"
	"eta/eta_api/models/semantic_analysis"
	"eta/eta_api/models/system"
	"eta/eta_api/services"
	_interface "eta/eta_api/services/interface"
	"eta/eta_api/utils"
	"fmt"
	"github.com/rdlucklib/rdluck_tools/http"
	"os"
	"path"
	"strconv"
	"strings"
	"time"
)

func materialClassifyHaveChild(allNode []*material.MaterialClassifyItems, node *material.MaterialClassifyItems) (childs []*material.MaterialClassifyItems, yes bool) {
	for _, v := range allNode {
		if v.ParentId == node.ClassifyId {
			childs = append(childs, v)
		}
	}
	if len(childs) > 0 {
		yes = true
	}
	return
}

func MaterialClassifyItemsMakeTree(sysUser *system.Admin, allNode []*material.MaterialClassifyItems, node *material.MaterialClassifyItems) {

	childs, _ := materialClassifyHaveChild(allNode, node) //判断节点是否有子节点并返回
	if len(childs) > 0 {

		node.Children = append(node.Children, childs[0:]...) //添加子节点
		for _, v := range childs {                           //查询子节点的子节点,并添加到子节点
			_, has := materialClassifyHaveChild(allNode, v)
			if has {
				MaterialClassifyItemsMakeTree(sysUser, allNode, v) //递归添加节点
			} else {
				childrenArr := make([]*material.MaterialClassifyItems, 0)
				v.Children = childrenArr
			}
		}
	} else {
		childrenArr := make([]*material.MaterialClassifyItems, 0)
		node.Children = childrenArr
	}
}

func BatchAddMaterial(materialList []material.BatchAddMaterialItem, classifyId, opUserId int, opUserName string) (err error) {
	addList := make([]*material.Material, 0)
	sort, err := material.GetMaterialMaxSort()
	if err != nil {
		return
	}
	for _, v := range materialList {
		sort = sort + 1
		addList = append(addList, &material.Material{
			MaterialName:    v.MaterialName,
			MaterialNameEn:  v.MaterialName,
			ImgUrl:          v.ImgUrl,
			SysUserId:       opUserId,
			SysUserRealName: opUserName,
			ModifyTime:      time.Now(),
			CreateTime:      time.Now(),
			ClassifyId:      classifyId,
			Sort:            sort,
		})
	}
	if len(addList) > 0 {
		err = material.AddMultiMaterial(addList)
	}
	return
}

// AddToMaterial 将图库等封面上传至素材库
func AddToMaterial(req material.SaveAsMaterialReq, opUserId int, opUserName string) (err error, errMsg string) {
	// 判断出对应的类型,得倒最终的资源地址
	oldRsourceUrl := ""
	switch req.ObjectType {
	case "chart":
		// 获取图表封面地址
		chartInfo, e := data_manage.GetChartInfoById(req.ObjectId)
		if e != nil {
			if e.Error() == utils.ErrNoRow() {
				errMsg = "图表不存在"
				err = fmt.Errorf("图表不存在")
				return
			}
			errMsg = "获取图表信息失败"
			err = e
			return
		}
		if chartInfo.ChartImage == "" {
			errMsg = "图表封面为空"
			err = fmt.Errorf("图表封面为空")
			return
		}
		oldRsourceUrl = chartInfo.ChartImage
	case "sandbox":
		// 获取逻辑图
		sandboxInfo, e := sandbox.GetSandboxById(req.ObjectId)
		if e != nil {
			if e.Error() == utils.ErrNoRow() {
				errMsg = "逻辑图不存在"
				err = fmt.Errorf("逻辑图不存在")
				return
			}
			errMsg = "获取逻辑图信息失败"
			err = e
			return
		}
		if sandboxInfo.PicUrl == "" { // 获取逻辑图封面地址
			errMsg = "逻辑图封面为空"
			err = fmt.Errorf("逻辑图封面为空")
			return
		}
		oldRsourceUrl = sandboxInfo.PicUrl
	case "excel":
		// 获取表格封面地址
		excelInfo, e := excel.GetExcelViewInfoByExcelInfoId(req.ObjectId)
		if e != nil {
			if e.Error() == utils.ErrNoRow() {
				errMsg = "表格不存在"
				err = fmt.Errorf("表格不存在")
				return
			}
			errMsg = "获取表格信息失败"
			err = e
			return
		}
		if excelInfo.ExcelImage == "" {
			errMsg = "表格封面为空"
			err = fmt.Errorf("表格封面为空")
			return
		}
		oldRsourceUrl = excelInfo.ExcelImage
	case "sa_doc":
		// 获取文档封面地址
		docObj := new(semantic_analysis.SaCompare)
		e := docObj.GetItemById(req.ObjectId)
		if e != nil { // 获取文档信息
			if e.Error() == utils.ErrNoRow() {
				errMsg = "文档不存在"
				err = fmt.Errorf("文档不存在")
				return
			}
			errMsg = "获取文档信息失败"
			err = e
			return
		}
		if docObj.ResultImg == "" {
			errMsg = "文档封面为空"
			err = fmt.Errorf("文档封面为空")
			return
		}

		oldRsourceUrl = docObj.ResultImg
	default:
		errMsg = "不支持的类型"
		err = fmt.Errorf("不支持的类型")
		return
	}

	resourceUrl, err, errMsg := uploadToMaterial(oldRsourceUrl)
	if err != nil {
		return
	}
	// 新增素材库

	sort, err := material.GetMaterialMaxSort()
	if err != nil {
		return
	}
	//素材主表信息
	materialInfo := &material.Material{
		MaterialName:    utils.TrimStr(req.MaterialName),
		MaterialNameEn:  utils.TrimStr(req.MaterialName),
		ImgUrl:          utils.TrimStr(resourceUrl),
		SysUserId:       opUserId,
		SysUserRealName: opUserName,
		ModifyTime:      time.Now(),
		CreateTime:      time.Now(),
		ClassifyId:      req.ClassifyId,
		Sort:            sort + 1,
	}

	//新增素材
	id, err := material.AddMaterial(materialInfo)
	if err != nil {
		return
	}
	materialInfo.MaterialId = int(id)
	return
}

// MyChartAddToMaterial 将我的
func MyChartAddToMaterial(req material.MyChartSaveAsMaterialReq, opUserId int, opUserName string) (err error, errMsg string) {
	// 判断出对应的类型,得倒最终的资源地址
	// 获取图表ID
	chartInfoIds := make([]int, 0)
	for _, v := range req.MaterialList {
		chartInfoIds = append(chartInfoIds, v.ChartInfoId)
	}
	// 获取图表信息
	if len(chartInfoIds) <= 0 {
		return
	}
	chartInfoList, e := data_manage.GetChartInfoByIdList(chartInfoIds)
	if e != nil {
		if e.Error() == utils.ErrNoRow() {
			errMsg = "图表不存在"
			err = fmt.Errorf("图表不存在")
			return
		}
		errMsg = "获取图表信息失败"
		err = e
		return
	}
	chartInfoMap := make(map[int]string)
	for _, v := range chartInfoList {
		if v.ChartImage == "" {
			errMsg = "图表封面为空"
			err = fmt.Errorf("图表封面为空")
			return
		}
		chartInfoMap[v.ChartInfoId] = v.ChartImage
	}
	addList := make([]*material.Material, 0)
	sort, err := material.GetMaterialMaxSort()
	if err != nil {
		return
	}
	for _, v := range req.MaterialList {
		sort = sort + 1
		oldResourceUrl, ok := chartInfoMap[v.ChartInfoId]
		if !ok {
			return
		}
		resourceUrl := ""
		resourceUrl, err, errMsg = uploadToMaterial(oldResourceUrl)
		if err != nil {
			return
		}
		// 新增素材库

		//素材主表信息
		materialInfo := &material.Material{
			MaterialName:    utils.TrimStr(v.MaterialName),
			MaterialNameEn:  utils.TrimStr(v.MaterialName),
			ImgUrl:          utils.TrimStr(resourceUrl),
			SysUserId:       opUserId,
			SysUserRealName: opUserName,
			ModifyTime:      time.Now(),
			CreateTime:      time.Now(),
			ClassifyId:      v.ClassifyId,
			Sort:            sort,
		}
		addList = append(addList, materialInfo)
	}
	if len(addList) > 0 {
		err = material.AddMultiMaterial(addList)
	}
	return
}
func uploadToMaterial(oldRsourceUrl string) (resourceUrl string, err error, errMsg string) {
	// 下载资源地址内容,并上传至存储空间得倒最终的素材地址
	urlFileName := path.Base(oldRsourceUrl)
	uploadDir := utils.STATIC_DIR + "hongze/" + time.Now().Format("20060102")
	if e := os.MkdirAll(uploadDir, utils.DIR_MOD); e != nil {
		errMsg = "存储目录创建失败"
		err = fmt.Errorf("存储目录创建失败, Err:" + e.Error())
		return
	}
	var content []byte
	content, err = http.Get(oldRsourceUrl)
	if err != nil {
		errMsg = "操作失败"
		err = fmt.Errorf("资源获取失败, Err: " + err.Error())
		return
	}
	filePath := uploadDir + "/" + urlFileName
	ioWriter, err := os.Create(filePath)
	if err != nil {
		errMsg = "操作失败"
		err = fmt.Errorf("文件创建失败, Err: " + err.Error())
		return
	}
	n, err := ioWriter.Write(content)
	fmt.Println("n", n)
	if err != nil {
		errMsg = "操作失败"
		err = fmt.Errorf("压缩文件写入失败, Err: " + err.Error())
		return
	}
	ext := path.Ext(urlFileName)
	randStr := utils.GetRandStringNoSpecialChar(28)
	newFileName := randStr + ext

	// 上传到阿里云
	ossDir := utils.RESOURCE_DIR + "material_dir/"
	savePath := ossDir + time.Now().Format("200601/20060102/") + newFileName
	// 上传文件
	ossClient := services.NewOssClient()
	if ossClient == nil {
		err = fmt.Errorf("初始化OSS服务失败")
		return
	}
	resourceUrl, err = ossClient.UploadFile(newFileName, filePath, savePath)
	if err != nil {
		err = fmt.Errorf("文件上传失败, Err: %s", err.Error())
		return
	}

	defer func() {
		os.Remove(filePath)
	}()
	return
}

func MoveMaterialClassify(classifyInfo *material.MaterialClassify, req *material.MoveMaterialClassifyReq) (err error, errMsg string) {
	nodeMove := models.SingleMoveNodeReq{}
	nodeMove.NodeId = req.ClassifyId
	nodeMove.ParentNodeId = req.ParentClassifyId
	nodeMove.PrevNodeId = req.PrevClassifyId
	nodeMove.NextNodeId = req.NextClassifyId

	materialClassifyMove := new(ClassifyMove)

	nodeInfo, updateCol, err, errMsg := _interface.MoveSingleNode(materialClassifyMove, nodeMove)
	if err != nil {
		return
	}
	oldParentId := classifyInfo.ParentId
	oldLevelPath := classifyInfo.LevelPath
	if len(updateCol) > 0 {
		classifyInfo.Sort = nodeInfo.Sort
		classifyInfo.ModifyTime = nodeInfo.ModifyTime
		classifyInfo.ParentId = nodeInfo.ParentId

		levelPath := classifyInfo.LevelPath
		if classifyInfo.ParentId != oldParentId {
			//查找父级分类
			parentClassify, e := material.GetMaterialClassifyById(classifyInfo.ParentId)
			if e != nil {
				errMsg = "获取父级分类失败"
				err = fmt.Errorf("获取父级分类失败,Err:" + e.Error())
				return
			}
			levelPath = fmt.Sprintf("%s%d,", parentClassify.LevelPath, classifyInfo.ClassifyId)
			classifyInfo.LevelPath = levelPath
			updateCol = append(updateCol, "LevelPath")
		}
		err = classifyInfo.Update(updateCol)
		if err != nil {
			err = fmt.Errorf("修改失败,Err:" + err.Error())
			return
		}

		if classifyInfo.ParentId != oldParentId {
			tmpList, e := material.GetMaterialClassifyByLevelPath(oldLevelPath)
			if e != nil {
				err = fmt.Errorf("保存分类失败,Err:" + e.Error())
				return
			}
			// 把原先的父级levePath,替换成最新的父级序列
			for _, tmp := range tmpList {
				//获取字符串前缀的位置
				after, _ := strings.CutPrefix(tmp.LevelPath, oldLevelPath)
				fmt.Println("after", after)
				// 拼接字符串
				if after != "" {
					tmp.LevelPath = levelPath + after
					tmp.ModifyTime = time.Now()
					e = tmp.Update([]string{"LevelPath", "ModifyTime"})
					if e != nil {
						err = fmt.Errorf("修改子分类,Err:" + e.Error())
						return
					}
				}
			}
		}
	}
	return
}

type ClassifyMove struct{}

func (m *ClassifyMove) GetNodeInfoById(nodeId int) (nodeInfo *models.NodeInfo, err error) {
	classifyInfo, err := material.GetMaterialClassifyById(nodeId)
	if err != nil {
		return
	}
	nodeInfo = &models.NodeInfo{
		NodeId:     classifyInfo.ClassifyId,
		NodeName:   classifyInfo.ClassifyName,
		ParentId:   classifyInfo.ParentId,
		Level:      classifyInfo.Level,
		Sort:       classifyInfo.Sort,
		ModifyTime: classifyInfo.ModifyTime,
	}
	return
}

func (m *ClassifyMove) UpdateNodeInfoSortByParentIdAndSource(parentNodeId, nodeId, prevNodeSort int, updateSortStr string, nodeType int) (err error) {
	err = material.UpdateMaterialClassifySortByParentId(parentNodeId, nodeId, prevNodeSort, updateSortStr)
	return
}

func (m *ClassifyMove) GetNodeMaxSort(parentId, nodeType int) (maxSort int, err error) {
	maxSort, err = material.GetMaterialClassifyMaxSort(parentId)
	return
}

func (m *ClassifyMove) GetFirstNodeInfoByParentId(parentId int) (nodeInfo *models.NodeInfo, err error) {
	classifyInfo, err := material.GetFirstMaterialClassifyByParentId(parentId)
	if err != nil {
		return
	}
	nodeInfo = &models.NodeInfo{
		NodeId:     classifyInfo.ClassifyId,
		NodeName:   classifyInfo.ClassifyName,
		ParentId:   classifyInfo.ParentId,
		Level:      classifyInfo.Level,
		Sort:       classifyInfo.Sort,
		ModifyTime: classifyInfo.ModifyTime,
	}
	return
}

func GetBatchSelectedMaterialList(classifyId int, keyword string, isShowMe bool, sysUser *system.Admin, lang string) (list []*material.MaterialListItems, err error, errMsg string) {
	var condition string
	var pars []interface{}

	if classifyId <= 0 {
		errMsg = "请选择分类"
		err = fmt.Errorf(errMsg)
		return
	}
	// 查询当前的分类
	classifyInfo, e := material.GetMaterialClassifyById(classifyId)
	if e != nil {
		errMsg = "分类不存在"
		err = fmt.Errorf("获取分类信息失败,Err:" + e.Error())
		return
	}
	// 获取所有子分类
	childList, e := material.GetMaterialClassifyByLevelPath(classifyInfo.LevelPath)
	if e != nil {
		errMsg = "获取分类失败"
		err = fmt.Errorf("获取子分类失败,Err:" + e.Error())
		return
	}
	// 把原先的父级levePath,替换成最新的父级序列
	classifyIdMap := make(map[string]struct{})
	classifyIds := make([]string, 0)
	childClassifyMap := make(map[int]*material.MaterialClassify)
	for _, tmp := range childList {
		childClassifyMap[tmp.ClassifyId] = tmp
		//获取字符串前缀的位置
		after, _ := strings.CutPrefix(tmp.LevelPath, classifyInfo.LevelPath)
		fmt.Println("after", after)
		// 拼接字符串
		if after != "" {
			ids := strings.Split(after, ",")
			for _, v := range ids {
				if _, ok := classifyIdMap[v]; !ok {
					classifyIds = append(classifyIds, v)
					classifyIdMap[v] = struct{}{}
				}
			}
		}
	}
	classifyIds = append(classifyIds, strconv.Itoa(classifyId))
	if len(classifyIds) > 0 {
		condition += " AND classify_id IN(" + utils.GetOrmInReplace(len(classifyIds)) + ") "
		pars = append(pars, classifyIds)
	}

	if keyword != "" {
		switch lang {
		case utils.LANG_EN:
			condition += ` AND  ( material_name_en LIKE '%` + keyword + `%' )`
		default:
			condition += ` AND  ( material_name LIKE '%` + keyword + `%' )`
		}
	}

	//只看我的
	if isShowMe {
		condition += ` AND sys_user_id = ? `
		pars = append(pars, sysUser.AdminId)
	}

	//获取图表信息
	list, err = material.GetMaterialListByCondition(condition, pars)
	if err != nil && err.Error() != utils.ErrNoRow() {
		errMsg = "获取素材库信息失败"
		err = fmt.Errorf("获取素材库信息失败,Err:" + err.Error())
		return
	}
	return
}

func GetMyChartExistMaterialNameListMsg(nameList map[string]struct{}, reqList []*material.MyChartSaveAsMaterialItem) (nameResp material.MyChartSaveAsMaterialResp) {
	existNameList := make([]*material.MyChartSaveAsMaterialItem, 0)
	for _, v := range reqList {
		if _, ok := nameList[v.MaterialName]; ok {
			existNameList = append(existNameList, v)
		}
	}
	nameResp = material.MyChartSaveAsMaterialResp{
		ExistList: existNameList,
	}
	return
}