package services

import (
	"archive/zip"
	"encoding/json"
	"errors"
	"eta/eta_mobile/models"
	"eta/eta_mobile/models/report"
	"eta/eta_mobile/models/report_approve"
	"eta/eta_mobile/models/system"
	"eta/eta_mobile/utils"
	"fmt"
	"github.com/rdlucklib/rdluck_tools/file"
	"github.com/rdlucklib/rdluck_tools/http"
	html2 "golang.org/x/net/html"
	"net/url"
	"os"
	"path"
	"strconv"
	"strings"
	"time"

	"github.com/beego/beego/v2/server/web"
	"github.com/beego/beego/v2/server/web/context"
	"github.com/go-redis/redis/v8"
)

// AddReportAndChapter
// @Description: 新增报告（包含章节）
// @author: Roc
// @datetime 2024-06-04 11:23:20
// @param reportInfo *models.Report
// @param inheritReportId int
// @return err error
// @return errMsg string
func AddReportAndChapter(reportInfo *models.Report, inheritReportId int, grantAdminIdList []int, reportDate time.Time) (err error, errMsg string) {
	// 根据审批开关及审批流判断当前报告状态
	state, e := CheckReportCurrState(report_approve.FlowReportTypeChinese, reportInfo.ClassifyIdFirst, reportInfo.ClassifyIdSecond, reportInfo.ClassifyIdThird, models.ReportOperateAdd)
	if e != nil {
		//errMsg = "操作失败"
		err = errors.New("校验报告当前状态失败, Err: " + e.Error())
		return
	}
	// 报告状态
	reportInfo.State = state

	// 获取最小分类id
	minClassifyId := reportInfo.ClassifyIdThird
	if minClassifyId <= 0 {
		minClassifyId = reportInfo.ClassifyIdSecond
	}
	if minClassifyId <= 0 {
		minClassifyId = reportInfo.ClassifyIdFirst
	}
	if minClassifyId <= 0 {
		errMsg = "分类异常"
		err = errors.New(errMsg)
		return
	}

	errMsg = "生成报告失败"

	// 报告继承
	if inheritReportId > 0 {
		inheritReport, tmpErr := models.GetReportByReportId(inheritReportId)
		if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
			errMsg = "获取待继承的报告失败"
			err = tmpErr
			return
		}
		if inheritReport != nil {
			// 判断当前的报告分类与继承的报告分类是否一致
			if inheritReport.ClassifyIdFirst != reportInfo.ClassifyIdFirst || inheritReport.ClassifyIdSecond != reportInfo.ClassifyIdSecond || inheritReport.ClassifyIdThird != reportInfo.ClassifyIdThird {
				errMsg = "分类异常，与继承的报告分类不一致"
				err = errors.New(errMsg)
				return
			}

			reportInfo.ChapterType = inheritReport.ChapterType
			reportInfo.Content = inheritReport.Content
			reportInfo.ContentSub = inheritReport.ContentSub
			reportInfo.ContentStruct = inheritReport.ContentStruct
			reportInfo.CanvasColor = inheritReport.CanvasColor
			//reportInfo.NeedSplice = inheritReport.NeedSplice
			reportInfo.NeedSplice = 1
			reportInfo.HeadResourceId = inheritReport.HeadResourceId
			//reportInfo.HeadImg = inheritReport.HeadImg
			//reportInfo.EndImg = inheritReport.EndImg
			reportInfo.HeadImg = ``
			reportInfo.EndImg = ``
			reportInfo.EndResourceId = inheritReport.EndResourceId
			if inheritReport.HeadResourceId > 0 {
				reportInfo.HeadImg = inheritReport.HeadImg
			}
			if inheritReport.EndResourceId > 0 {
				reportInfo.EndImg = inheritReport.EndImg
			}
			reportInfo.InheritReportId = inheritReport.Id
		}
	}

	// 获取待生成的报告章节
	addChapterList, allGrantUserList, err, errMsg := getAddChapter(reportInfo, minClassifyId, inheritReportId, grantAdminIdList, reportDate)

	// 新增报告及章节
	var reportId int64
	reportId, err = models.AddReportAndChapter(reportInfo, allGrantUserList, addChapterList)
	if err != nil {
		err = errors.New("新增报告及章节失败, Err: " + err.Error())
		return
	}
	reportCode := utils.MD5(strconv.Itoa(reportInfo.Id))
	reportInfo.ReportCode = reportCode

	// 修改唯一编码
	{
		go models.ModifyReportCode(reportId, reportCode)
	}

	// 报告权限处理
	go handleReportPermission(reportId, minClassifyId)

	return
}

// EditReport
// @Description: 修改报告的基础信息、授权用户权限
// @author: Roc
// @datetime 2024-06-06 17:16:58
// @param reportInfo *models.Report
// @param req models.EditReq
// @param sysUser *system.Admin
// @return err error
// @return errMsg string
func EditReport(reportInfo *models.Report, req models.EditReq, sysUser *system.Admin) (err error, errMsg string) {
	errMsg = `保存失败`
	oldIsPublicPublish := reportInfo.IsPublicPublish
	//var stage int
	//if reportInfo.ClassifyNameFirst != req.ClassifyNameFirst || reportInfo.ClassifyNameSecond != req.ClassifyNameSecond {
	//	// 报告期数
	//	maxStage, _ := models.GetReportStageEdit(req.ClassifyIdFirst, req.ClassifyIdSecond, req.ClassifyIdThird, int(req.ReportId))
	//	maxStage = maxStage + 1
	//	stage = maxStage
	//} else {
	//	stage = reportInfo.Stage
	//}

	//if req.State != reportInfo.State {
	//	recordItem := &models.ReportStateRecord{
	//		ReportId:   int(req.ReportId),
	//		ReportType: 1,
	//		State:      req.State,
	//		AdminId:    this.SysUser.AdminId,
	//		AdminName:  this.SysUser.AdminName,
	//		CreateTime: time.Now(),
	//	}
	//	go func() {
	//		_, _ = models.AddReportStateRecord(recordItem)
	//	}()
	//}

	//item := new(models.Report)
	//reportInfo.ClassifyIdFirst = req.ClassifyIdFirst
	//reportInfo.ClassifyNameFirst = req.ClassifyNameFirst
	//reportInfo.ClassifyIdSecond = req.ClassifyIdSecond
	//reportInfo.ClassifyNameSecond = req.ClassifyNameSecond
	//reportInfo.ClassifyIdThird = req.ClassifyIdThird
	//reportInfo.ClassifyNameThird = req.ClassifyNameThird
	reportInfo.Title = req.Title
	reportInfo.Abstract = req.Abstract
	reportInfo.Author = req.Author
	reportInfo.Frequency = req.Frequency
	//reportInfo.State = reportInfo.State // 编辑不变更状态
	//reportInfo.Stage = stage // 编辑不变更期数
	//reportInfo.Content = html.EscapeString(req.Content)	// 编辑不变更具体内容
	//reportInfo.ContentSub = html.EscapeString(contentSub)	// 编辑不变更具体内容
	reportInfo.CreateTime = req.CreateTime
	//reportInfo.CollaborateType = req.CollaborateType
	//reportInfo.ReportLayout = req.ReportLayout
	if req.IsPublicPublish <= 0 {
		req.IsPublicPublish = 1
	}
	reportInfo.IsPublicPublish = req.IsPublicPublish
	reportInfo.LastModifyAdminId = sysUser.AdminId
	reportInfo.LastModifyAdminName = sysUser.RealName
	reportInfo.ModifyTime = time.Now()

	state, e := CheckReportCurrState(report_approve.FlowReportTypeChinese, reportInfo.ClassifyIdFirst, reportInfo.ClassifyIdSecond, reportInfo.ClassifyIdThird, models.ReportOperateEdit)
	if e != nil {
		//errMsg = "操作失败"
		err = errors.New("校验报告当前状态失败, Err: " + e.Error())
		return
	}
	// 报告状态
	reportInfo.State = state

	//updateCols := []string{"ClassifyIdFirst", "ClassifyNameFirst", "ClassifyIdSecond", "ClassifyNameSecond", "ClassifyIdThird", "ClassifyNameThird", "Title", "Abstract", "Author", "Frequency", "Stage", "CreateTime", "IsPublicPublish", "LastModifyAdminId", "LastModifyAdminName", "ModifyTime"}
	updateCols := []string{"Title", "Abstract", "Author", "Frequency", "CreateTime", "IsPublicPublish", "LastModifyAdminId", "LastModifyAdminName", "ModifyTime", "State"}

	if req.HeadResourceId > 0 {
		reportInfo.HeadResourceId = req.HeadResourceId
		updateCols = append(updateCols, "HeadResourceId")
	}
	if req.EndResourceId > 0 {
		reportInfo.EndResourceId = req.EndResourceId
		updateCols = append(updateCols, "EndResourceId")
	}

	// 需要添加的报告授权数据
	addReportAdminList := make([]*report.ReportGrant, 0)
	// 待移除的报告授权数据id
	delReportGrantIdList := make([]int, 0)

	// 处理当前报告需要新增/移除的授权信息
	{
		reportGrantObj := report.ReportGrant{}
		// 获取当前报告已经授权的用户信息
		reportGrantList, tmpErr := reportGrantObj.GetGrantListById(reportInfo.Id)
		if tmpErr != nil {
			err = tmpErr
			return
		}

		// 当前报告已经授权的用户信息
		currReportAdminMap := make(map[int]*report.ReportGrant)
		// 需要删除的报告授权数据
		delReportAdminMap := make(map[int]*report.ReportGrant)
		for _, v := range reportGrantList {
			currReportAdminMap[v.AdminId] = v
			delReportAdminMap[v.AdminId] = v
		}

		// 先看需要新增哪些用户
		for _, tmpAdminId := range req.GrantAdminIdList {
			_, ok := currReportAdminMap[tmpAdminId]
			// 如果章节中需要新增的用户 已经在 报告授权用户里面，那么就忽略，可以不用新增了
			if ok {
				delete(delReportAdminMap, tmpAdminId)
				continue
			}

			// 如果不存在，那么就新增授权
			addReportAdminList = append(addReportAdminList, &report.ReportGrant{
				//GrantId:         0,
				ReportId:   reportInfo.Id,
				AdminId:    tmpAdminId,
				CreateTime: time.Now(),
			})
		}

		// 查出需要移除的授权id
		for _, v := range delReportAdminMap {
			delReportGrantIdList = append(delReportGrantIdList, v.GrantId)
		}
	}

	// 修改报告的基本信息，以及报告的授权用户
	err = models.EditReportAndPermission(reportInfo, updateCols, addReportAdminList, delReportGrantIdList)
	if err != nil {
		return
	}

	// 报告权限处理
	{
		minClassifyId, _, tmpErr := getMinClassify(reportInfo)
		if tmpErr != nil {
			return
		}
		go handleReportPermission(int64(reportInfo.Id), minClassifyId)
	}

	// 更新es里的章节数据
	if oldIsPublicPublish != reportInfo.IsPublicPublish {
		if reportInfo.HasChapter == 1 {
			// 晨周报
			chapterList, tmpErr := models.GetPublishedChapterListByReportId(reportInfo.Id)
			if tmpErr != nil {
				return
			}
			if len(chapterList) > 0 {
				// 更新章节的es数据
				for _, chapterInfo := range chapterList {
					err = updateReportChapterEsByChapter(chapterInfo, reportInfo.IsPublicPublish)
					if err != nil {
						return
					}
				}
			}
		}
	}

	return
}

// getAddChapter
// @Description: 获取待新增的报告章节列表
// @author: Roc
// @datetime 2024-06-04 13:10:58
// @param reportInfo *models.Report
// @param minClassifyId int
// @param inheritReportId int
// @param grantAdminIdList []int
// @return chapterList []*models.ReportChapter
// @return err error
// @return errMsg string
func getAddChapter(reportInfo *models.Report, minClassifyId, inheritReportId int, grantAdminIdList []int, reportDate time.Time) (chapterList []models.AddReportChapter, allGrantUserList []*report.ReportGrant, err error, errMsg string) {
	// 待生成的报告章节内容
	chapterList = make([]models.AddReportChapter, 0)

	// 所有的授权用户
	allGrantUserList = make([]*report.ReportGrant, 0)
	// 报告授权的用户ID
	needAdminIdMap := make(map[int]bool)
	for _, adminId := range grantAdminIdList {
		needAdminIdMap[adminId] = true
		allGrantUserList = append(allGrantUserList, &report.ReportGrant{
			//GrantId:      0,
			//ReportId:     0,
			AdminId:    adminId,
			CreateTime: time.Now(),
		})
	}
	if reportInfo.HasChapter != 1 {
		return
	}

	// 最小单元的分类
	var minClassifyName string
	if reportInfo.ClassifyIdThird == minClassifyId {
		minClassifyName = reportInfo.ClassifyNameThird
	} else if reportInfo.ClassifyIdSecond == minClassifyId {
		minClassifyName = reportInfo.ClassifyNameSecond
	} else {
		minClassifyName = reportInfo.ClassifyNameFirst
	}

	errMsg = "生成报告章节失败"
	// 章节类型列表
	allTypeList, err := models.GetReportChapterTypeListByClassifyId(minClassifyId)
	if err != nil {
		err = errors.New(errMsg)
		return
	}

	// 待添加的章节
	chapterTypeList := make([]*models.ReportChapterType, 0)
	// 待添加的章节类型id列表
	chapterTypeIdList := make([]int, 0)

	//nowTime := time.Now().Local()
	for _, chapterType := range allTypeList {
		// 如果被永久暂停更新了
		if chapterType.Enabled == 0 { //该章节已被永久禁用，那么就不允许继承或者新增该章节
			continue
		}

		if chapterType.PauseStartTime != "" && chapterType.PauseEndTime != "" && chapterType.PauseStartTime != utils.EmptyDateStr && chapterType.PauseEndTime != utils.EmptyDateStr {
			startTime, timeErr := time.ParseInLocation(utils.FormatDate, chapterType.PauseStartTime, time.Local)
			if timeErr != nil {
				utils.FileLog.Error("更新规则时间转换失败4001, Err: " + timeErr.Error())
				continue
			}
			endTime, timeErr := time.ParseInLocation(utils.FormatDate, chapterType.PauseEndTime, time.Local)
			if timeErr != nil {
				utils.FileLog.Error("更新规则时间转换失败4002, Err: " + timeErr.Error())
				continue
			}
			// 暂停更新(此处用报告日期去判断是否需要停更，而不是报告创建日期)
			if !reportDate.Before(startTime) && !reportDate.After(endTime) {
				continue
			}
		}

		// 正常的章节类型状态，那么应该自动创建该章节
		chapterTypeList = append(chapterTypeList, chapterType)
		chapterTypeIdList = append(chapterTypeIdList, chapterType.ReportChapterTypeId)
	}

	// 待继承的章节类id的授权用户
	oldChapterIdGrantListMap := make(map[int][]*report.ReportChapterGrant)
	// 待继承的章节类id关联的品种列表
	oldChapterPermissionListMap := make(map[int][]*report.ReportChapterPermissionMapping)
	// 自定义章节列表
	customAddChapterList := make([]models.AddReportChapter, 0)
	// 报告继承
	inheritChapterMap := make(map[int]*models.ReportChapter)

	// 当前分类下配置的章节类型id所关联的品种列表（默认配置，不是从继承报告里面获取的，如果有继承章节，那么需要从继承报告里面获取）
	currChapterTypePermissionListMap := make(map[int][]*report.ReportChapterPermissionMapping)

	if len(chapterTypeIdList) > 0 {
		mappingList, e := models.GetChapterTypePermissionByChapterTypeIdList(chapterTypeIdList)
		if e != nil {
			err = fmt.Errorf("获取章节类型权限列表失败, Err: " + e.Error())
			return
		}
		hasPermissionMap := make(map[string]bool)
		for _, v := range mappingList {
			tmpChapterTypePermissionList, ok := currChapterTypePermissionListMap[v.ReportChapterTypeId]
			if !ok {
				tmpChapterTypePermissionList = make([]*report.ReportChapterPermissionMapping, 0)
			}
			key := fmt.Sprint(v.ReportChapterTypeId, "-", v.ChartPermissionId)
			if _, has := hasPermissionMap[key]; !has {
				hasPermissionMap[key] = true
				currChapterTypePermissionListMap[v.ReportChapterTypeId] = append(tmpChapterTypePermissionList, &report.ReportChapterPermissionMapping{
					ReportChapterPermissionMappingId: 0,
					ReportChapterId:                  0,
					ChartPermissionId:                v.ChartPermissionId,
					CreateTime:                       time.Now(),
				})
			}
		}
	}

	if inheritReportId > 0 {
		// 继承待继承的报告章节内容
		inheritReportChapters, tmpErr := models.GetChapterListByReportId(inheritReportId)
		if tmpErr != nil {
			errMsg = "获取待继承的报告章节失败"
			err = tmpErr
			return
		}
		reportChaptersIdList := make([]int, 0)
		for _, v := range inheritReportChapters {
			reportChaptersIdList = append(reportChaptersIdList, v.ReportChapterId)
		}

		// 继承的报告章节用户map
		grantListMap := make(map[int][]*report.ReportChapterGrant)

		// 继承的报告章节的关联品种map
		chapterPermissionListMap := make(map[int][]*report.ReportChapterPermissionMapping)

		// 授权数据列表
		if len(reportChaptersIdList) > 0 {
			// 授权用户数据
			obj := report.ReportChapterGrant{}
			grantList, tmpErr := obj.GetGrantListByIdList(reportChaptersIdList)
			if tmpErr != nil {
				errMsg = "获取待继承的报告章节的授权用户列表失败"
				err = tmpErr
				return
			}

			for _, v := range grantList {
				// 如果不在报告授权的用户ID里面，那么该章节就不继承该授权用户
				if _, ok := needAdminIdMap[v.AdminId]; !ok {
					continue
				}

				currReportChapterId := v.ReportChapterId
				tmpGrantList, ok := grantListMap[currReportChapterId]
				if !ok {
					tmpGrantList = make([]*report.ReportChapterGrant, 0)
				}
				v.ReportChapterId = 0
				v.GrantId = 0
				tmpGrantList = append(tmpGrantList, v)
				grantListMap[currReportChapterId] = tmpGrantList
			}

			// 授权关联品种数据
			permissionObj := report.ReportChapterPermissionMapping{}
			permissionList, tmpErr := permissionObj.GetPermissionListByIdList(reportChaptersIdList)
			if tmpErr != nil {
				errMsg = "获取待继承的报告章节的授权用户列表失败"
				err = tmpErr
				return
			}

			for _, v := range permissionList {
				currReportChapterId := v.ReportChapterId
				tmpPermissionList, ok := chapterPermissionListMap[currReportChapterId]
				if !ok {
					tmpPermissionList = make([]*report.ReportChapterPermissionMapping, 0)
				}
				v.ReportChapterId = 0
				v.ReportChapterPermissionMappingId = 0
				tmpPermissionList = append(tmpPermissionList, v)
				chapterPermissionListMap[currReportChapterId] = tmpPermissionList
			}
		}

		// 继承的报告章节内容
		for i := 0; i < len(inheritReportChapters); i++ {
			customChapter := inheritReportChapters[i]

			// 授权用户列表
			tmpGrantList, ok := grantListMap[customChapter.ReportChapterId]
			if !ok {
				tmpGrantList = make([]*report.ReportChapterGrant, 0)
			}
			oldChapterIdGrantListMap[customChapter.ReportChapterId] = tmpGrantList

			// 关联品种列表
			chapterPermissionList, ok := chapterPermissionListMap[customChapter.ReportChapterId]
			if !ok {
				chapterPermissionList = make([]*report.ReportChapterPermissionMapping, 0)
			}
			oldChapterPermissionListMap[customChapter.ReportChapterId] = chapterPermissionList

			// 判断该章节是否是系统章节，如果是的话，那就是需要额外创建的
			if customChapter.TypeId > 0 {
				inheritChapterMap[customChapter.TypeId] = customChapter
				continue
			}

			// 自定义的报告内容
			customChapter.ReportId = reportInfo.Id
			customChapter.ReportChapterId = 0
			customChapter.ClassifyIdFirst = minClassifyId
			customChapter.ClassifyNameFirst = minClassifyName
			customChapter.Stage = reportInfo.Stage
			customChapter.PublishState = 1
			customChapter.CreateTime = reportInfo.CreateTime
			customChapter.ModifyTime = time.Now()
			customChapter.LastModifyAdminId = reportInfo.LastModifyAdminId
			customChapter.LastModifyAdminName = reportInfo.LastModifyAdminName
			customChapter.ContentModifyTime = time.Now()

			customAddChapter := models.AddReportChapter{
				ReportChapter:       customChapter,
				GrantList:           tmpGrantList,
				GrantPermissionList: chapterPermissionList,
			}
			customAddChapterList = append(customAddChapterList, customAddChapter)
		}
	}

	// 最大排序
	var maxSort int
	for _, typeItem := range chapterTypeList {
		v, ok := inheritChapterMap[typeItem.ReportChapterTypeId]

		// 章节授权用户
		var tmpGrantList []*report.ReportChapterGrant
		// 章节关联品种
		var tmpChapterPermissionList []*report.ReportChapterPermissionMapping

		chapterItem := new(models.ReportChapter)

		if ok && v != nil {
			// 如果存在继承的章节，那么就从继承的章节内容中获取
			chapterItem.AddType = 2
			chapterItem.Title = v.Title
			chapterItem.ReportType = v.ReportType
			chapterItem.ClassifyIdFirst = minClassifyId
			chapterItem.ClassifyNameFirst = minClassifyName
			chapterItem.TypeId = typeItem.ReportChapterTypeId
			chapterItem.TypeName = typeItem.ReportChapterTypeName
			chapterItem.Content = v.Content
			chapterItem.ContentSub = v.ContentSub
			chapterItem.Stage = reportInfo.Stage
			chapterItem.PublishState = 1
			chapterItem.Sort = typeItem.Sort
			chapterItem.CreateTime = reportInfo.CreateTime
			chapterItem.ModifyTime = time.Now()

			chapterItem.LastModifyAdminId = reportInfo.LastModifyAdminId
			chapterItem.LastModifyAdminName = reportInfo.LastModifyAdminName
			chapterItem.ContentModifyTime = time.Now()
			chapterItem.ContentStruct = v.ContentStruct
			chapterItem.ReportLayout = v.ReportLayout
			chapterItem.ReportCreateTime = time.Now()

			// 继承历史章节中的授权用户列表
			tmpGrantList, ok = oldChapterIdGrantListMap[v.ReportChapterId]
			if !ok {
				tmpGrantList = make([]*report.ReportChapterGrant, 0)
			}
			// 继承历史章节中的关联品种列表
			tmpChapterPermissionList, ok = oldChapterPermissionListMap[v.ReportChapterId]
			if !ok {
				tmpChapterPermissionList = make([]*report.ReportChapterPermissionMapping, 0)
			}
		} else {
			// 如果系统章节未从继承的报告中找到，那么获取往期中最新版本的此章节内容
			var findChapter bool
			if inheritReportId > 0 {
				chapterNewest, e := models.GetNewestPreReportChapterByClassifyIdAndTypeId(minClassifyId, typeItem.ReportChapterTypeId)
				if e != nil && e.Error() == utils.ErrNoRow() {
					errMsg = "继承最新内容的章节失败"
					err = fmt.Errorf("获取最新内容的章节失败, %v", e)
					return
				}
				if chapterNewest != nil {
					chapterItem.AddType = 2
					chapterItem.Title = chapterNewest.Title
					chapterItem.ReportType = chapterNewest.ReportType
					chapterItem.ClassifyIdFirst = minClassifyId
					chapterItem.ClassifyNameFirst = minClassifyName
					chapterItem.TypeId = typeItem.ReportChapterTypeId
					chapterItem.TypeName = typeItem.ReportChapterTypeName
					chapterItem.Content = chapterNewest.Content
					chapterItem.ContentSub = chapterNewest.ContentSub
					chapterItem.Stage = reportInfo.Stage
					chapterItem.PublishState = 1
					chapterItem.Sort = typeItem.Sort
					chapterItem.CreateTime = reportInfo.CreateTime
					chapterItem.ModifyTime = time.Now()
					chapterItem.LastModifyAdminId = reportInfo.LastModifyAdminId
					chapterItem.LastModifyAdminName = reportInfo.LastModifyAdminName
					chapterItem.ContentModifyTime = time.Now()
					chapterItem.ContentStruct = chapterNewest.ContentStruct
					chapterItem.ReportLayout = chapterNewest.ReportLayout
					chapterItem.ReportCreateTime = time.Now()

					// 这里的授权和品种权限需要额外查询
					tmpGrantList = make([]*report.ReportChapterGrant, 0)
					tmpChapterPermissionList = make([]*report.ReportChapterPermissionMapping, 0)
					{
						grantOb := report.ReportChapterGrant{}
						chapterGrant, e := grantOb.GetGrantListById(chapterNewest.ReportChapterId)
						if e != nil {
							errMsg = "获取待继承的报告章节的授权用户列表失败"
							err = fmt.Errorf("获取待继承的报告章节的授权用户列表失败, ChapterId: %d, Err: %v", chapterNewest.ReportChapterId, e)
							return
						}
						for _, cg := range chapterGrant {
							// 如果不在报告授权的用户ID里面，那么该章节就不继承该授权用户
							if _, ok := needAdminIdMap[cg.AdminId]; !ok {
								continue
							}
							cg.ReportChapterId = 0
							cg.GrantId = 0
							tmpGrantList = append(tmpGrantList, cg)
						}

						permissionOb := report.ReportChapterPermissionMapping{}
						permissions, e := permissionOb.GetPermissionListById(chapterNewest.ReportChapterId)
						if e != nil {
							errMsg = "获取待继承的报告章节的品种权限失败"
							err = fmt.Errorf("获取待继承的报告章节的品种权限失败, ChapterId: %d, Err: %v", chapterNewest.ReportChapterId, e)
							return
						}
						for _, ps := range permissions {
							ps.ReportChapterId = 0
							ps.ReportChapterPermissionMappingId = 0
							tmpChapterPermissionList = append(tmpChapterPermissionList, ps)
						}
					}

					findChapter = true
				}
			}

			// 没找到那就新增一篇空白的
			if !findChapter {
				chapterItem.AddType = 1
				chapterItem.Title = typeItem.ReportChapterTypeName
				chapterItem.ReportType = typeItem.ResearchType
				chapterItem.ClassifyIdFirst = minClassifyId
				chapterItem.ClassifyNameFirst = minClassifyName
				chapterItem.TypeId = typeItem.ReportChapterTypeId
				chapterItem.TypeName = typeItem.ReportChapterTypeName
				chapterItem.Stage = reportInfo.Stage
				chapterItem.PublishState = 1
				chapterItem.Sort = typeItem.Sort
				chapterItem.CreateTime = reportInfo.CreateTime
				chapterItem.ModifyTime = time.Now()

				chapterItem.LastModifyAdminId = reportInfo.LastModifyAdminId
				chapterItem.LastModifyAdminName = reportInfo.LastModifyAdminName
				chapterItem.ContentModifyTime = time.Now()
				//chapterItem.ContentStruct = v.ContentStruct
				chapterItem.ReportLayout = reportInfo.ReportLayout
				chapterItem.ReportCreateTime = time.Now()

				// 默认配置：从当前分类下配置的章节类型id所关联的品种列表
				tmpChapterPermissionList, ok = currChapterTypePermissionListMap[typeItem.ReportChapterTypeId]
				if !ok {
					tmpChapterPermissionList = make([]*report.ReportChapterPermissionMapping, 0)
				}
			}
		}

		if typeItem.Sort > maxSort {
			maxSort = typeItem.Sort
		}

		addChapter := models.AddReportChapter{
			ReportChapter:       chapterItem,
			GrantList:           tmpGrantList,
			GrantPermissionList: tmpChapterPermissionList,
		}

		chapterList = append(chapterList, addChapter)
	}

	// 将自定义的章节内容添加到待生成的章节内容中
	for _, addChapterItem := range customAddChapterList {
		maxSort++
		addChapterItem.ReportChapter.Sort = maxSort
		chapterList = append(chapterList, addChapterItem)
	}

	//hasGrantUserMap := make(map[int]bool)
	//for _, grantList := range typeGrantListMap {
	//	for _, grant := range grantList {
	//		if _, ok := hasGrantUserMap[grant.AdminId]; !ok {
	//			allGrantUserList = append(allGrantUserList, &report.ReportGrant{
	//				//GrantId:      0,
	//				//ReportId:     0,
	//				AdminId:    grant.AdminId,
	//				CreateTime: time.Now(),
	//			})
	//		}
	//	}
	//}

	return
}

// AddChapterBaseInfoAndPermission
// @Description:  添加章节基本信息及权限
// @author: Roc
// @datetime 2024-06-11 15:35:23
// @param reportInfo *models.Report
// @param reportChapterInfo *models.ReportChapter
// @param permissionIdList []int
// @param adminIdList []int
// @return err error
// @return errMsg string
func AddChapterBaseInfoAndPermission(reportInfo *models.Report, reportChapterInfo *models.ReportChapter, permissionIdList []int, adminIdList []int) (err error, errMsg string) {
	errMsg = "新增失败"

	if reportInfo.State == 2 {
		errMsg = "该报告已发布，不允许编辑"
		err = errors.New(errMsg)
		return
	}

	// 需要添加的报告章节授权数据
	addChapterAdminList := make([]*report.ReportChapterGrant, 0)
	for _, adminId := range adminIdList {
		//新增授权
		addChapterAdminList = append(addChapterAdminList, &report.ReportChapterGrant{
			//GrantId:         0,
			//ReportChapterId: reportChapterInfo.ReportChapterId,
			AdminId:    adminId,
			CreateTime: time.Now(),
		})
	}

	// 需要添加的报告章节品种权限数据
	addChapterPermissionList := make([]*report.ReportChapterPermissionMapping, 0)
	// 品种权限
	for _, permissionId := range permissionIdList {
		// 如果不存在，那么就新增品种权限配置
		addChapterPermissionList = append(addChapterPermissionList, &report.ReportChapterPermissionMapping{
			//ReportChapterPermissionMappingId:         0,
			//ReportChapterId:   reportChapterInfo.ReportChapterId,
			ChartPermissionId: permissionId,
			CreateTime:        time.Now(),
		})
	}

	err = models.AddChapterBaseInfoAndPermission(reportChapterInfo, addChapterAdminList, addChapterPermissionList)

	return
}

// EditChapterBaseInfoAndPermission
// @Description: 修改报告章节的基础信息、授权用户权限、品种权限
// @author: Roc
// @datetime 2024-06-05 11:49:11
// @param reportInfo *models.Report
// @param reportChapterInfo *models.ReportChapter
// @param title string
// @param permissionIdList []int
// @param adminIdList []int
// @return err error
// @return errMsg string
func EditChapterBaseInfoAndPermission(reportInfo *models.Report, reportChapterInfo *models.ReportChapter, title string, permissionIdList []int, adminIdList []int) (err error, errMsg string) {
	errMsg = "修改失败"

	if reportInfo.State == 2 {
		errMsg = "该报告已发布，不允许编辑"
		err = errors.New(errMsg)
		return
	}

	updateCols := make([]string, 0)
	// 如果标题内容，那么就修改
	if title != `` {
		reportChapterInfo.Title = title
		reportChapterInfo.ModifyTime = time.Now()
		updateCols = append(updateCols, "Title", "ModifyTime")
		reportChapterInfo.UpdateChapter(updateCols)
	}

	reportGrantObj := report.ReportGrant{}
	chapterGrantObj := report.ReportChapterGrant{}
	chapterPermissionObj := report.ReportChapterPermissionMapping{}

	// 报告授权的用户map
	reportGrantAdminIdMap := make(map[int]bool)
	// 获取报告授权的用户信息
	{
		// 获取当前报告已经授权的用户信息
		reportGrantList, tmpErr := reportGrantObj.GetGrantListById(reportInfo.Id)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		for _, v := range reportGrantList {
			reportGrantAdminIdMap[v.AdminId] = true
		}
	}

	// 需要添加的报告章节授权数据
	addChapterAdminList := make([]*report.ReportChapterGrant, 0)
	// 待移除的报告章节授权数据id
	delReportChapterGrantIdList := make([]int, 0)

	// 处理当前报告章节需要新增/移除的授权信息
	{
		// 获取当前章节已经授权的用户信息
		chapterGrantList, tmpErr := chapterGrantObj.GetGrantListById(reportChapterInfo.ReportChapterId)
		if tmpErr != nil {
			err = tmpErr
			return
		}

		// 当前章节已经授权的用户信息
		currChapterAdminMap := make(map[int]*report.ReportChapterGrant)
		// 需要删除的报告章节授权数据
		delChapterAdminMap := make(map[int]*report.ReportChapterGrant)
		for _, v := range chapterGrantList {
			currChapterAdminMap[v.AdminId] = v
			delChapterAdminMap[v.AdminId] = v
		}

		for _, adminId := range adminIdList {
			// 如果该用户 不在 报告授权的用户map 里面，说明这个用户是要移除的
			if _, ok := reportGrantAdminIdMap[adminId]; !ok {
				continue
			}
			_, ok := currChapterAdminMap[adminId]
			// 如果存在，那么从 “需要删除的报告章节授权数据” 的map中移除
			if ok {
				delete(delChapterAdminMap, adminId)
				continue
			}
			// 如果不存在，那么就新增授权
			addChapterAdminList = append(addChapterAdminList, &report.ReportChapterGrant{
				//GrantId:         0,
				ReportChapterId: reportChapterInfo.ReportChapterId,
				AdminId:         adminId,
				CreateTime:      time.Now(),
			})
		}

		// 查出需要移除的授权id
		for _, v := range delChapterAdminMap {
			delReportChapterGrantIdList = append(delReportChapterGrantIdList, v.GrantId)
		}
	}

	// 其他章节授权的用户
	otherChapterAdminMap := make(map[int]bool)
	{
		// 获取报告所有的章节id
		reportChapterIdList, tmpErr := models.GetReportChapterIdList(reportInfo.Id)
		if tmpErr != nil {
			err = tmpErr
			return
		}

		if len(reportChapterIdList) > 0 {
			list, tmpErr := chapterGrantObj.GetGrantListByIdList(reportChapterIdList)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			for _, v := range list {
				// 如果是当前章节，因为涉及到重新授权，所以得过滤
				if v.ReportChapterId == reportChapterInfo.ReportChapterId {
					continue
				}
				otherChapterAdminMap[v.AdminId] = true
			}
		}
	}

	// 需要添加的报告章节品种权限数据
	addChapterPermissionList := make([]*report.ReportChapterPermissionMapping, 0)
	// 待移除的报告章节品种权限数据id
	delChapterPermissionMappingIdList := make([]int, 0)

	// 处理当前报告章节需要新增/移除的品种权限信息
	{
		// 获取当前章节已经配置的品种权限信息
		chapterPermissionList, tmpErr := chapterPermissionObj.GetPermissionListById(reportChapterInfo.ReportChapterId)
		if tmpErr != nil {
			err = tmpErr
			return
		}

		// 当前章节已经配置的品种权限信息
		currChapterPermissionMap := make(map[int]*report.ReportChapterPermissionMapping)
		// 需要删除的报告章节品种权限配置
		delChapterPermissionMap := make(map[int]*report.ReportChapterPermissionMapping)
		for _, v := range chapterPermissionList {
			currChapterPermissionMap[v.ChartPermissionId] = v
			delChapterPermissionMap[v.ChartPermissionId] = v
		}

		for _, permissionId := range permissionIdList {
			_, ok := currChapterPermissionMap[permissionId]
			// 如果存在，那么从 “需要删除的报告章节品种权限配置” 的map中移除
			if ok {
				delete(delChapterPermissionMap, permissionId)
				continue
			}
			// 如果不存在，那么就新增品种权限配置
			addChapterPermissionList = append(addChapterPermissionList, &report.ReportChapterPermissionMapping{
				//ReportChapterPermissionMappingId:         0,
				ReportChapterId:   reportChapterInfo.ReportChapterId,
				ChartPermissionId: permissionId,
				CreateTime:        time.Now(),
			})
		}

		// 查出需要移除的品种权限配置
		for _, v := range delChapterPermissionMap {
			delChapterPermissionMappingIdList = append(delChapterPermissionMappingIdList, v.ReportChapterPermissionMappingId)
		}
	}

	err = models.EditChapterBaseInfoAndPermission(reportInfo, reportChapterInfo, updateCols, addChapterAdminList, addChapterPermissionList, delReportChapterGrantIdList, delChapterPermissionMappingIdList)

	return
}

// DelChapter
// @Description: 删除报告章节、授权用户权限、品种权限
// @author: Roc
// @datetime 2024-06-06 17:28:37
// @param reportInfo *models.Report
// @param reportChapterInfo *models.ReportChapter
// @param sysUser *system.Admin
// @return err error
// @return errMsg string
func DelChapter(reportInfo *models.Report, reportChapterInfo *models.ReportChapter, sysUser *system.Admin) (err error, errMsg string) {
	errMsg = "删除失败"
	if reportInfo.State == 2 {
		errMsg = "该报告已发布，不允许删除"
		err = errors.New(errMsg)
		return
	}

	reportInfo.LastModifyAdminId = sysUser.AdminId
	reportInfo.LastModifyAdminName = sysUser.RealName
	reportInfo.ModifyTime = time.Now()
	updateReportCols := []string{"LastModifyAdminId", "LastModifyAdminName", "ModifyTime"}
	err = models.DelChapterAndPermission(reportInfo, updateReportCols, reportChapterInfo)

	return
}

// DownloadVoice
// @Description:  下载报告音频文件
// @author: Roc
// @datetime 2024-06-13 15:36:46
// @param reportInfo *models.ReportDetail
// @return savePath string
// @return fileName string
// @return err error
// @return errMsg string
func DownloadVoice(reportInfo *models.ReportDetail) (savePath, fileName string, err error, errMsg string) {
	errMsg = `下载失败`
	// 如果报告有音频，那么下载音频
	if reportInfo.VideoUrl != `` {
		savePath = time.Now().Format(utils.FormatDateTimeUnSpace) + utils.GetRandString(5) + ".mp3"
		fileName = reportInfo.VideoName + ".mp3"
		fileBody, tmpErr := http.Get(reportInfo.VideoUrl)
		if tmpErr != nil {
			err = tmpErr
			errMsg = "音频下载失败"
			return
		}
		err = file.SaveFile(fileBody, savePath)
		if err != nil {
			errMsg = "音频保存失败"
			return
		}
	}

	// 如果是章节报告，那么就下载压缩包
	if reportInfo.HasChapter == 1 {
		videoList, tmpErr := models.GetReportChapterVideoList(reportInfo.Id)
		if tmpErr != nil {
			err = tmpErr
			errMsg = "获取音频列表失败"
			return
		}

		if len(videoList) > 0 {
			// 创建zip
			savePath = time.Now().Format(utils.FormatDateTimeUnSpace) + utils.GetRandString(5) + ".zip"
			fileName = reportInfo.VideoName + ".zip"

			zipFile, tmpErr := os.Create(savePath)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			zipWriter := zip.NewWriter(zipFile)
			// 生成zip过程中报错关闭
			defer func() {
				if err != nil {
					zipWriter.Close()
					zipFile.Close()
				}
			}()

			// 获取音频,写入zip
			for i := 0; i < len(videoList); i++ {
				item := videoList[i]
				if item.VideoName == "" || item.VideoUrl == "" {
					continue
				}
				// 音频文件后缀
				ext := path.Ext(item.VideoUrl)
				ioWriter, tmpErr := zipWriter.Create(fmt.Sprintf("%s%s", item.VideoName, ext))
				if tmpErr != nil {
					err = tmpErr
					if os.IsPermission(err) {
						fmt.Println("权限不足: ", err)
						return
					}
					return
				}

				var content []byte
				content, err = http.Get(item.VideoUrl)
				if err != nil {
					content = []byte("")
				}

				ioWriter.Write(content)
			}
			// 生成zip后关闭,否则下载文件会损坏
			zipWriter.Close()
			zipFile.Close()
		}
	}

	return
}

// CheckReportAuthByAdminIdList
// @Description: 根据管理员id列表，判断当前用户是否有报告权限
// @author: Roc
// @datetime 2024-06-13 11:03:10
// @param adminId int
// @param createAdminId int
// @param grantAdminIdList []int
// @return isAuth bool
func CheckReportAuthByAdminIdList(adminId, createAdminId int, grantAdminIdList []int) (isAuth bool) {
	// 如果是自己创建的报告，那么就有权限
	if adminId == createAdminId {
		isAuth = true
		return
	}
	// 如果是授权用户，那么就有权限
	if utils.IsCheckInList(grantAdminIdList, adminId) {
		isAuth = true
		return
	}

	return
}

// CheckReportAuthByReportId
// @Description: 根据报告ID，判断当前用户是否有报告权限
// @author: Roc
// @datetime 2024-06-13 16:21:28
// @param adminId int
// @param reportInfoId int
// @return isAuth bool
// @return err error
func CheckReportAuthByReportId(sysUser *system.Admin, createAdminId int, reportInfoId int) (isAuth bool, err error) {
	// 如果是自己创建的报告，那么就有权限
	if sysUser.AdminId == createAdminId {
		isAuth = true
		return
	}
	// 如果本人是超管，那么就有权限
	if utils.IsAdminRole(sysUser.RoleTypeCode) {
		isAuth = true
		return
	}

	obj := report.ReportGrant{}
	item, err := obj.GetGrantByIdAndAdmin(reportInfoId, sysUser.AdminId)
	if err != nil {
		// 如果是没找到数据，那么就是无权限
		if err.Error() == utils.ErrNoRow() {
			err = nil
			return
		}
		// sql报错了
		return
	}
	// 用户id一致就有权限
	if item.AdminId == sysUser.AdminId {
		isAuth = true
	}

	return
}

// EditReportLayoutImg
// @Description: 修改报告的版图信息
// @author: Roc
// @datetime 2024-06-18 11:35:00
// @param reportInfo *models.Report
// @param req models.EditLayoutImgReq
// @param sysUser *system.Admin
// @return err error
// @return errMsg string
func EditReportLayoutImg(reportInfo *models.Report, req models.EditLayoutImgReq, sysUser *system.Admin) (err error, errMsg string) {
	errMsg = `保存失败`

	reportInfo.HeadResourceId = req.HeadResourceId
	reportInfo.HeadImg = req.HeadImg
	reportInfo.EndResourceId = req.EndResourceId
	reportInfo.EndImg = req.EndImg
	reportInfo.CanvasColor = req.CanvasColor
	reportInfo.LastModifyAdminId = sysUser.AdminId
	reportInfo.LastModifyAdminName = sysUser.RealName
	reportInfo.ModifyTime = time.Now()

	updateCols := []string{"HeadResourceId", "HeadImg", "EndResourceId", "EndImg", "CanvasColor", "LastModifyAdminId", "LastModifyAdminName", "ModifyTime"}

	err = reportInfo.UpdateReport(updateCols)
	if err != nil {
		return
	}

	return
}

// PublishReport
// @Description: 报告发布
// @author: Roc
// @datetime 2024-06-20 09:44:13
// @param reportId int
// @param reportUrl string
// @param sysUser *system.Admin
// @return tips string
// @return err error
// @return errMsg string
func PublishReport(reportId int, reportUrl string, sysUser *system.Admin) (tips string, err error, errMsg string) {
	errMsg = `报告发布失败`
	reportInfo, err := models.GetReportByReportId(reportId)
	if err != nil {
		errMsg = "获取报告信息失败"
		return
	}
	if reportInfo == nil {
		errMsg = "获取报告信息失败"
		err = errors.New(errMsg)
		return
	}

	var publishTime time.Time
	if reportInfo.MsgIsSend == 1 && reportInfo.PublishTime.IsZero() { //如果报告曾经发布过，并且已经发送过模版消息，则章节的发布时间为报告的发布时间
		publishTime = reportInfo.PublishTime
	} else {
		publishTime = time.Now()
	}
	var tmpErr error

	// 章节类型的报告（原来的晨周报）
	if reportInfo.HasChapter == 1 {
		tips, tmpErr, errMsg = PublishChapterReport(reportInfo, reportUrl, sysUser)
		if tmpErr != nil {
			err = errors.New("晨周报发布失败, Err:" + tmpErr.Error() + ", report_id:" + strconv.Itoa(reportId))
		}
		return
	}

	// 普通报告
	if reportInfo.Content == "" {
		errMsg = `报告内容为空，不可发布`
		err = errors.New("报告内容为空，不需要生成,report_id:" + strconv.Itoa(reportId))
		return
	}

	// 根据审批开关及审批流判断当前报告状态
	state, e := CheckReportCurrState(report_approve.FlowReportTypeChinese, reportInfo.ClassifyIdFirst, reportInfo.ClassifyIdSecond, reportInfo.ClassifyIdThird, models.ReportOperatePublish)
	if e != nil {
		errMsg = "操作失败"
		err = errors.New("校验报告当前状态失败, Err: " + e.Error())
		return
	}

	if state == models.ReportStatePublished {
		// 发布报告
		if tmpErr = models.PublishReportById(reportId, publishTime, sysUser.AdminId, sysUser.RealName); tmpErr != nil {
			err = errors.New("报告发布失败, Err:" + tmpErr.Error() + ", report_id:" + strconv.Itoa(reportId))
			return
		}
		go func() {
			// 生成音频
			if reportInfo.VideoUrl == "" {
				go UpdateReportVideo(reportInfo)
			}
			// 更新报告Es
			_ = UpdateReportEs(reportId, 2)
		}()
	} else {
		// 从无审批切换为有审批, 状态重置
		if e = models.ResetReportById(reportId, state, sysUser.AdminId, sysUser.RealName); e != nil {
			errMsg = "操作失败"
			err = fmt.Errorf("重置报告状态失败, Err: %s, ReportId: %d", e.Error(), reportId)
			return
		}
	}

	recordItem := &models.ReportStateRecord{
		ReportId:   reportId,
		ReportType: 1,
		State:      state,
		AdminId:    sysUser.AdminId,
		AdminName:  sysUser.AdminName,
		CreateTime: time.Now(),
	}
	go func() {
		_, _ = models.AddReportStateRecord(recordItem)
	}()

	// 生成报告pdf和长图
	{
		reportPdfUrl := GetGeneralPdfUrl(reportInfo.Id, reportInfo.ReportCode, reportInfo.ReportLayout)
		go Report2pdfAndJpeg(reportPdfUrl, reportId, 1)
	}

	// 报告权限处理
	{
		minClassifyId, _, tmpErr := getMinClassify(reportInfo)
		if tmpErr != nil {
			return
		}
		go handleReportPermission(int64(reportInfo.Id), minClassifyId)
	}

	return
}

// PublishChapterReport
// @Description: 发布章节类型的报告
// @author: Roc
// @datetime 2024-06-28 10:38:50
// @param reportInfo *models.Report
// @param reportUrl string
// @return tips string
// @return err error
// @return errMsg string
func PublishChapterReport(reportInfo *models.Report, reportUrl string, sysUser *system.Admin) (tips string, err error, errMsg string) {
	reportId := reportInfo.Id
	if reportInfo.State == 2 {
		return
	}

	// 获取所有章节列表
	chapters, err := models.GetChapterListByReportId(reportId)
	if err != nil {
		return
	}
	chapterLen := len(chapters)
	if chapterLen <= 0 {
		tips = "报告章节为空，不可发布"
		errMsg = tips
		err = errors.New(tips)
		return
	}

	// 获取报告中的所有章节列表
	chapterList, err := models.GetChapterListByReportId(reportId)
	if err != nil {
		return
	}
	for _, chapter := range chapterList {
		if chapter.PublishState == 1 {
			tips = "还存在未发布的章节"
			errMsg = tips
			err = errors.New(tips)
			return
		}
	}

	// 根据审批开关及审批流判断当前报告状态
	state, e := CheckReportCurrState(report_approve.FlowReportTypeChinese, reportInfo.ClassifyIdFirst, reportInfo.ClassifyIdSecond, reportInfo.ClassifyIdThird, models.ReportOperatePublish)
	if e != nil {
		//errMsg = "操作失败"
		err = errors.New("校验报告当前状态失败, Err: " + e.Error())
		return
	}

	// 如果状态不是已发布，那么就重置状态
	if state != models.ReportStatePublished {
		// 从无审批切换为有审批, 状态重置
		if e = models.ResetReportById(reportId, state, sysUser.AdminId, sysUser.RealName); e != nil {
			//errMsg = "操作失败"
			err = fmt.Errorf("重置报告状态失败, Err: %s, ReportId: %d", e.Error(), reportId)
			return
		}
		return
	}

	// 需发布整期
	updateCols := make([]string, 0)
	reportInfo.LastModifyAdminId = sysUser.AdminId
	reportInfo.LastModifyAdminName = sysUser.RealName
	updateCols = append(updateCols, "LastModifyAdminId", "LastModifyAdminName", "Title", "State", "ModifyTime")

	// 发布后标题调整
	//title := reportInfo.Title
	//title = strings.ReplaceAll(title, "【弘则FICC晨报】", "")
	//title = strings.ReplaceAll(title, "【弘则FICC周报】", "")
	//if title == "" {
	//	// 取第一个需发布章节的标题
	//	firstId := publishIdArr[0]
	//	firstTitle := ""
	//	for i := 0; i < chapterLen; i++ {
	//		if chapters[i].ReportChapterId == firstId {
	//			firstTitle = chapters[i].Title
	//			break
	//		}
	//	}
	//	title = firstTitle
	//}
	//report.Title = title
	reportInfo.State = state

	// 研报后台4.4 只在没有发布过时更新发布时间，其余均按模版消息发送时间当作发布时间
	if reportInfo.MsgIsSend == 0 || reportInfo.PublishTime.IsZero() {
		reportInfo.PublishTime = time.Now().Local()
		updateCols = append(updateCols, "PublishTime")

	}
	reportInfo.ModifyTime = time.Now().Local()

	if e := models.PublishReportAndChapter(reportInfo, true, updateCols); e != nil {
		err = errors.New("发布报告及章节失败")
		return
	}
	// 生成章节音频
	go UpdateReportVideo(reportInfo)

	// 更新报告ES
	go func() {
		_ = UpdateReportEs(reportInfo.Id, 2)
	}()

	// 发布时备份内容
	go SaveReportLogs(reportInfo, chapters, reportInfo.AdminId, reportInfo.AdminRealName)

	// 生成报告pdf和长图
	{
		reportPdfUrl := GetGeneralPdfUrl(reportInfo.Id, reportInfo.ReportCode, reportInfo.ReportLayout)
		go Report2pdfAndJpeg(reportPdfUrl, reportId, 1)
	}

	return
}

// DeleteReportAndChapter 删除报告及章节
func DeleteReportAndChapter(reportId int) (err error) {
	reportInfo, err := models.GetReportByReportId(reportId)
	if err != nil {
		err = errors.New("报告信息有误, Err: " + err.Error())
		return
	}
	if reportInfo.State == 2 {
		err = errors.New("报告已发布，不可删除")
		return
	}
	// 更新ES
	_ = UpdateReportEs(reportId, 1)
	// 删除
	if reportInfo.HasChapter == 1 {
		err = models.DeleteDayWeekReportAndChapter(reportId)
	} else {
		err = models.DeleteReport(reportId)
	}
	if err != nil {
		err = errors.New("删除失败, Err: " + err.Error())
		return
	}
	// 重置PPT关联报告
	go func() {
		_ = ResetPPTReport(reportId, false)
	}()

	return
}

// getMinClassify
// @Description: 获取最小分类ID
// @author: Roc
// @datetime 2024-06-20 09:23:19
// @param reportInfo *models.Report
// @return minClassifyId int
// @return minClassifyName string
// @return err error
func getMinClassify(reportInfo *models.Report) (minClassifyId int, minClassifyName string, err error) {
	defer func() {
		if err != nil {
			utils.FileLog.Error("获取最小分类ID失败，报告ID：%d，Err：%s", reportInfo.Id, err.Error())
		}
	}()
	minClassifyId = reportInfo.ClassifyIdThird
	minClassifyName = reportInfo.ClassifyNameThird
	if minClassifyId <= 0 {
		minClassifyId = reportInfo.ClassifyIdSecond
		minClassifyName = reportInfo.ClassifyNameSecond
	}
	if minClassifyId <= 0 {
		minClassifyId = reportInfo.ClassifyIdFirst
		minClassifyName = reportInfo.ClassifyNameFirst
	}
	if minClassifyId <= 0 {
		err = errors.New("分类异常")
	}

	return
}

// handleReportPermission
// @Description: 报告权限处理
// @author: Roc
// @datetime 2024-06-19 18:00:51
// @param reportId int64
// @param minClassifyId int
func handleReportPermission(reportId int64, minClassifyId int) {
	// TODO 报告权限处理
	var err error
	defer func() {
		if err != nil {
			utils.FileLog.Error("报告权限处理失败，报告ID：%d，分类ID：%d，Err：%s", reportId, minClassifyId, err.Error())
			//alarm_msg.SendAlarmMsg("修改删除报告权限失败，Err："+err.Error(), 3)
		}
	}()

	err = models.RemoveChartPermissionChapterMapping(reportId)
	if err != nil {
		err = errors.New("修改删除报告权限失败，Err：" + err.Error())
		return
	}
	permissionItems, err := models.GetPermission(minClassifyId)
	if err != nil {
		err = errors.New("获取权限失败，Err：" + err.Error())
		return
	}
	for _, v := range permissionItems {
		err = models.AddChartPermissionChapterMapping(v.ChartPermissionId, reportId)
		if err != nil {
			err = errors.New("新增权限失败，Err：" + err.Error())
			return
		}
	}

	// 同步crm权限
	_ = EditReportPermissionSync(reportId, minClassifyId)

	return
}

// HandleReportPermission
// @Description: 报告权限处理
// @author: Roc
// @datetime 2024-07-12 11:17:49
// @param reportInfo *models.Report
func HandleReportPermission(reportInfo *models.Report) {
	minClassifyId, _, tmpErr := getMinClassify(reportInfo)
	if tmpErr != nil {
		return
	}
	handleReportPermission(int64(reportInfo.Id), minClassifyId)
}

// UpdateReportVideo
// @Description: 更新报告音频
// @author: Roc
// @datetime 2024-07-17 18:11:10
// @param reportInfo *models.Report
func UpdateReportVideo(reportInfo *models.Report) {
	if reportInfo.HasChapter == 1 {
		reportChapterIdList := make([]int, 0)
		// 获取报告中的所有章节列表
		chapterList, err := models.GetChapterListByReportId(reportInfo.Id)
		if err != nil {
			return
		}
		for _, chapter := range chapterList {
			if chapter.PublishState == 2 {
				reportChapterIdList = append(reportChapterIdList, chapter.ReportChapterId)
			}
		}
		if len(reportChapterIdList) > 0 {
			err = UpdateChaptersVideo(reportChapterIdList)
			if err != nil {
				utils.FileLog.Info(fmt.Sprintf("%d报告音频生产失败：%s", reportInfo.Id, err.Error()))
			}
		}
	} else {
		err := CreateVideo(reportInfo)
		if err != nil {
			utils.FileLog.Info(fmt.Sprintf("%d报告音频生产失败：%s", reportInfo.Id, err.Error()))
		}
	}
}

// GetGeneralPdfUrl
// @Description: 获取生成pdf的地址
// @author: Roc
// @datetime 2024-07-19 14:09:28
// @param reportCode string
// @param reportLayout int8
// @return pdfUrl string
func GetGeneralPdfUrl(reportId int, reportCode string, reportLayout int8) (pdfUrl string) {
	conf, e := models.GetBusinessConfByKey("ReportViewUrl")
	if e != nil {
		return
	}

	switch reportLayout {
	case 1:
		// 普通布局
		pdfUrl = fmt.Sprintf("%s/reportshare_pdf?code=%s", conf.ConfVal, reportCode)
	case 2:
		// 智能布局
		pdfUrl = fmt.Sprintf("%s/reportshare_smart_pdf?code=%s", conf.ConfVal, reportCode)
	}

	if pdfUrl != "" {
		token := utils.MD5(fmt.Sprint(pdfUrl, time.Now().UnixNano()/1e6))
		e := generalReportAuthToken(token, ``, reportId)
		if e == nil {
			pdfUrl = fmt.Sprintf("%s&authToken=%s", pdfUrl, token)
		}
	}

	return
}

// HandleReportContent
// @Description: 处理报告内容（动态图表/表格添加授权token）
// @author: Roc
// @datetime 2025-01-07 10:03:15
// @param body string
// @return newBody string
func HandleReportContent(body string, opType string, tokenMap map[string]string) (newBody string) {
	if body == `` {
		return
	}
	newBody = body

	// 解析HTML
	doc, err := html2.Parse(strings.NewReader(body))
	if err != nil {
		fmt.Println("Error parsing HTML:", err)
		return
	}

	replaceIframeSrc(doc, opType, tokenMap)

	// 输出修改后的HTML
	var modifiedHtml strings.Builder
	err = html2.Render(&modifiedHtml, doc)
	if err != nil {
		fmt.Println("Error rendering HTML:", err)
		return
	}

	newBody = modifiedHtml.String()
	fmt.Println(newBody)

	return
}

// replaceIframeSrc 遍历HTML节点，替换iframe的src属性
func replaceIframeSrc(n *html2.Node, opType string, tokenMap map[string]string) {
	if n.Type == html2.ElementNode && n.Data == "iframe" {
		for i, attr := range n.Attr {
			if attr.Key == "src" {
				newLink := attr.Val
				// 处理链接
				switch opType {
				case `add`:
					newLink = linkAddToken(attr.Val, tokenMap)
				case `del`:
					newLink = linkDelToken(attr.Val)
				}
				// 替换原来的链接
				n.Attr[i].Val = newLink
				break
			}
		}
	}
	// 递归处理子节点
	for c := n.FirstChild; c != nil; c = c.NextSibling {
		replaceIframeSrc(c, opType, tokenMap)
	}
}

// linkAddToken 链接添加token
func linkAddToken(link string, tokenMap map[string]string) string {
	var err error
	defer func() {
		if err != nil {
			utils.FileLog.Info("处理链接失败，ERR：" + err.Error())
		}
	}()
	parsedURL, err := url.Parse(link)
	if err != nil {
		return link
	}

	// 获取查询参数
	queryParams := parsedURL.Query()

	// 先移除authToken参数，避免莫名其妙的这个值入库了
	queryParams.Del("authToken")

	// 获取code参数
	code := queryParams.Get("code")
	if code == "" {
		return link
	}

	showType := `chart`
	if strings.Contains(parsedURL.Path, "sheetshow") {
		showType = `excel`
	}

	// 避免报告里面一个图表/表格重复生成token
	var token string
	key := fmt.Sprint(showType, `:`, code)
	if tokenMap != nil {
		token = tokenMap[key]
	}

	// 如果之前没有token，那么就重新生成token
	if token == `` {
		token, err = GeneralChartToken(showType, code, 30*time.Minute)
		if err != nil {
			return link
		}
	}

	if tokenMap != nil {
		tokenMap[key] = token
	}

	// 在链接后面添加一个token值
	queryParams.Add("authToken", token)

	// 更新URL的查询参数
	parsedURL.RawQuery = queryParams.Encode()

	return parsedURL.String()
}

// linkDelToken 链接添加token
func linkDelToken(link string) string {
	var err error
	defer func() {
		if err != nil {
			utils.FileLog.Info("处理链接失败，ERR：" + err.Error())
		}
	}()
	parsedURL, err := url.Parse(link)
	if err != nil {
		return link
	}

	// 获取查询参数
	queryParams := parsedURL.Query()

	// 移除authToken参数
	queryParams.Del("authToken")

	// 更新URL的查询参数
	parsedURL.RawQuery = queryParams.Encode()

	return parsedURL.String()
}

// GeneralChartToken
// @Description: 生产图表/表格授权token
// @author: Roc
// @datetime 2025-01-07 10:41:36
// @param showType string
// @param uniqueCode string
// @param expireTime time.Duration
// @return token string
// @return err error
func GeneralChartToken(showType, uniqueCode string, expireTime time.Duration) (token string, err error) {
	// 缓存key
	token = utils.MD5(fmt.Sprint(showType+`:`, uniqueCode, time.Now().UnixNano()/1e6))
	key := fmt.Sprint(utils.CACHE_CHART_AUTH, token)
	err = utils.Rc.Put(key, uniqueCode, expireTime)

	return
}

// GeneralReportToken
// @Description: 生成报告授权token
// @author: Roc
// @datetime 2025-01-07 10:41:36
// @param uniqueCode string
// @return token string
// @return err error
func GeneralReportToken(linkToken string, reportId int) (token string, err error) {
	// 图表授权token
	token = utils.MD5(fmt.Sprint(linkToken, time.Now().UnixNano()/1e6))

	// 缓存key
	reportKey := getReportShareTokenKey(linkToken)
	err = utils.Rc.Put(reportKey, token, utils.BusinessConfReportChartExpiredTime)
	if err != nil {
		return
	}

	// 生成报告的图表授权token
	err = generalReportAuthToken(token, ``, reportId)
	if err != nil {
		return
	}

	return
}

// generalReportAuthToken
// @Description: 生成报告的图表授权token
// @author: Roc
// @datetime 2025-03-17 17:47:07
// @param token string
// @param reportId int
// @return err error
func generalReportAuthToken(token, source string, reportId int) (err error) {
	// 缓存key
	reportTokenKey := getReportTokenKey(token, source)
	err = utils.Rc.Put(reportTokenKey, reportId, utils.BusinessConfReportChartExpiredTime)

	return
}

// getReportShareTokenKey
// @Description:
// @author: Roc
// @datetime 2025-03-17 14:00:14
// @param linkToken string
// @return string
func getReportShareTokenKey(linkToken string) string {
	return fmt.Sprint(utils.CACHE_REPORT_SHARE_AUTH, utils.MD5(linkToken))
}

// GetReportAuthToken
// @Description: 获取报告token
// @author: Roc
// @datetime 2025-03-17 16:48:38
// @param linkToken string
// @return string
func GetReportAuthToken(linkToken string) string {
	key := getReportShareTokenKey(linkToken)
	return utils.Rc.GetStr(key)

}

// getReportTokenKey
// @Description:
// @author: Roc
// @datetime 2025-03-17 14:00:14
// @param linkToken string
// @return string
func getReportTokenKey(token, source string) string {
	return fmt.Sprint(utils.CACHE_REPORT_AUTH, source, token)
}

// HandleReportContentStruct
// @Description: 处理内容组件的链接
// @author: Roc
// @datetime 2025-01-07 13:38:39
// @param body string
// @param opType string
// @return newBody string
func HandleReportContentStruct(body string, opType string, tokenMap map[string]string) (newBody string) {
	if body == `` {
		return
	}
	newBody = body

	// 解析JSON数据到map[string]interface{}
	var jsonData []map[string]interface{}
	if err := json.Unmarshal([]byte(body), &jsonData); err != nil {
		fmt.Println("Error parsing JSON:", err)
		return
	}

	// 处理每个组件
	for i := range jsonData {
		if err := processMap(jsonData[i], opType, tokenMap); err != nil {
			fmt.Println("Error processing component:", err)
			return
		}
	}

	// 将处理后的数据转换回JSON字符串
	modifiedJSON, err := json.MarshalIndent(jsonData, "", "  ")
	if err != nil {
		fmt.Println("Error marshaling JSON:", err)
		return
	}
	newBody = string(modifiedJSON)

	return
}

// processMap 递归处理map中的content字段
func processMap(data map[string]interface{}, opType string, tokenMap map[string]string) error {
	for key, value := range data {
		switch v := value.(type) {
		case string:
			if key == "content" {
				newContent := v
				// 处理链接
				switch opType {
				case `add`:
					newContent = linkAddToken(v, tokenMap)
				case `del`:
					newContent = linkDelToken(v)
				}
				data[key] = newContent
			}
		case map[string]interface{}:
			if err := processMap(v, opType, tokenMap); err != nil {
				return err
			}
		case []interface{}:
			for i := range v {
				if m, ok := v[i].(map[string]interface{}); ok {
					if err := processMap(m, opType, tokenMap); err != nil {
						return err
					}
				}
			}
		}
	}
	return nil
}

// GetReportShareUrlToken 获取报告分享链接token
func GetReportShareUrlToken(req models.ReportShartUrlReq, adminId int) (linkToken string, err error) {
	defer func() {
		if err == nil && linkToken != `` {
			GeneralReportToken(linkToken, req.ReportId)
		}
	}()
	cacheLinkKey := utils.CACHE_REPORT_SHARE_SHORT_Url + strconv.Itoa(req.ReportId) + "userId:" + strconv.Itoa(adminId)
	linkToken, _ = utils.Rc.RedisString(cacheLinkKey)
	if linkToken != "" && utils.Rc.IsExist(fmt.Sprint(utils.CACHE_REPORT_SHARE_ORIGIN_Url, utils.MD5(linkToken))) {
		return
	}
	var tokenKey string

	var ok bool
	// 冲突检测
	for i := 0; i < 3; i++ {
		linkToken = req.Url
		if i > 0 {
			linkToken += "_" + utils.GetRandDigit(3)
		}
		hashUrl := utils.MurmurHash64([]byte(linkToken))
		linkToken = utils.ConvertNumToBase62(hashUrl)
		// 拼上报告标题
		//linkToken = fmt.Sprintf("%s %s", linkToken, req.Title)

		tokenKey = fmt.Sprint(utils.CACHE_REPORT_SHARE_ORIGIN_Url, utils.MD5(linkToken))
		ok = utils.Rc.IsExist(tokenKey)
		if !ok {
			break
		}
	}
	if !ok {
		after := time.Now().AddDate(0, 0, 7)
		err = utils.Rc.Put(cacheLinkKey, linkToken, time.Until(after))
		if err != nil {
			return
		}
		err = utils.Rc.Put(tokenKey, req.Url, time.Until(after))
		if err != nil {
			return
		}
	} else {
		linkToken = ""
		err = errors.New("生成链接失败")
	}
	return
}

func TransfromToOriginUrl(linkToken string) (originLink string, msg string, err error) {
	cacheLinkKey := fmt.Sprint(utils.CACHE_REPORT_SHARE_ORIGIN_Url, utils.MD5(linkToken))
	originLink, err = utils.Rc.RedisString(cacheLinkKey)
	if err != nil {
		if err == redis.Nil {
			msg = "链接已失效, 请重新获取"
			return
		}
		msg = "获取链接失败"
		return
	}
	if originLink == "" {
		msg = "链接已失效, 请重新获取"
		return
	}

	reportToken := GetReportAuthToken(linkToken)
	if reportToken != "" {
		originLink += `&authToken=` + reportToken
	}

	return
}

func FilterShareUrl() web.FilterFunc {
	return func(c *context.Context) {
		path := c.Input.Context.Request.URL.Path
		tokenArr := strings.Split(path, "/")
		token := tokenArr[len(tokenArr)-1]

		newPath := "/v1/report/share/link"
		q := c.Input.Context.Request.URL.Query()
		q.Add("Token", token)
		c.Input.Context.Request.URL.Path = newPath
		c.Input.Context.Request.URL.RawQuery = q.Encode()

		utils.ApiLog.Info(fmt.Sprintf("原始请求为：%s, 已修改请求路径为：%s?%s", path, newPath, q.Encode()))
	}
}
