package services

//FICC研报
import (
	"context"
	"crypto/md5"
	"encoding/json"
	"errors"
	"fmt"
	html2 "golang.org/x/net/html"
	"hongze/hongze_cygx/models"
	"hongze/hongze_cygx/models/ficc_report"
	"hongze/hongze_cygx/utils"
	"html"
	"io/ioutil"
	"math"
	"net/http"
	"net/url"
	"sort"
	"strconv"
	"strings"
	"time"
)

// 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 *ficc_report.Report) (minClassifyId int, minClassifyName string, err error) {
	defer func() {
		if err != nil {
			go utils.SendAlarmMsg(fmt.Sprint("获取最小分类ID失败，报告ID：%d，Err：%s", reportInfo.Id, err.Error()), 2)
		}

	}()
	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
}

// 获取报告详情
func GetReportDetail(userinfo *models.WxUserItem, reportId int) (reportDetail ficc_report.ReportDetail, err error) {
	//var errMsg string
	defer func() {
		if err != nil {
			fmt.Println(err)
			go utils.SendAlarmMsg(fmt.Sprint("获取研报详情失败 GetReportDetail ，err：", err.Error(), "ReportId:", reportId), 2)
		}
	}()

	detailArticle, e := models.GetArticleDetailByReportId(reportId)
	if e != nil {
		err = errors.New("报告查询出错" + e.Error())
		return
	}

	reportInfo, e := ficc_report.GetByReportId(reportId)
	if e != nil {
		//errMsg = err.Error()
		err = errors.New("报告查询出错" + e.Error())
		return
	}
	if reportInfo.Id == 0 {
		err = errors.New("报告不存在")
		return
	}
	if reportInfo.State != 2 && reportInfo.State != 6 {
		err = errors.New("报告未发布")
		return
	}
	// 获取最小分类
	minClassifyId, _, err := GetMinClassify(reportInfo)

	// 判断报告是否属于专栏报告
	firstClassify, e := ficc_report.GetByClassifyId(reportInfo.ClassifyIdFirst)
	if e != nil {
		err = errors.New("报告一级分类有误")
		return
	}

	// 最小分类
	var minClassify *ficc_report.Classify
	if reportInfo.ClassifyIdFirst == minClassifyId {
		minClassify = firstClassify
	} else {
		minClassify, e = ficc_report.GetByClassifyId(minClassifyId)
		if e != nil {
			err = errors.New("报告最小层级分类有误")
			return
		}
	}
	var hasPermission int
	var hasPower bool
	if userinfo.CompanyId > 1 {
		companyPermission, e := models.GetCompanyPermission(userinfo.CompanyId)
		if e != nil {
			err = errors.New("GetCompanyPermission")
			return
		}
		if companyPermission != "" {
			slice := strings.Split(companyPermission, ",")
			if utils.InArrayByStr(slice, "周期") {
				hasPower = true
			}
		}
	}

	if hasPower {
		hasPermission = 1
	} else {
		if userinfo.UserId == 0 {
			hasPermission = 1
		} else {
			hasPermission, e = GetUserPermissionCode(userinfo.UserId, userinfo.CompanyId)
			if e != nil {
				err = errors.New("GetUserPermissionCode")
				return
			}
			reportDetail.SellerName, reportDetail.SellerMobile, _ = GetSellerName(userinfo)
		}

	}
	reportDetail.HasPermission = hasPermission

	//判断权限

	var authOk bool
	var reportChapterIdList []int
	if reportInfo.HasChapter == 1 {
		if reportInfo.ClassifyNameFirst == "晨报" {
			//authOk, permissionCheckInfo, err = CheckDayReportPermission(userinfo, productAuthOk)
		} else {
			_, _, _, reportChapterIdList, err = CheckWeekReportPermission(userinfo, reportId, true)
		}
	}
	if hasPermission == 1 {
		authOk = true
	}

	reportItem := new(ficc_report.ReportItem)
	reportItem.ReportId = reportInfo.Id
	reportItem.Title = reportInfo.Title
	reportItem.PublishTime = reportInfo.PublishTime
	reportItem.ClassifyNameFirst = reportInfo.ClassifyNameFirst
	reportItem.ClassifyNameSecond = reportInfo.ClassifyNameSecond
	reportItem.Stage = reportInfo.Stage
	reportItem.Abstract = reportInfo.Abstract
	reportItem.ContentSub = html.UnescapeString(reportInfo.ContentSub)
	reportItem.Frequency = reportInfo.Frequency
	reportItem.VideoName = reportInfo.VideoName
	reportItem.HasChapter = reportInfo.HasChapter
	reportItem.ReportLayout = reportInfo.ReportLayout
	reportItem.HeadImg = reportInfo.HeadImg
	reportItem.EndImg = reportInfo.EndImg
	reportItem.CanvasColor = reportInfo.CanvasColor
	reportItem.ArticleId = detailArticle.ArticleId
	reportItem.Disclaimer = GetConfigCodeDisclaimer()

	if reportInfo.ClassifyNameFirst == "晨会纪要" && reportInfo.ClassifyNameSecond == "晨会纪要" {
		reportItem.Title = "FICC/周期品晨会纪要"
	}

	//版头版尾样式
	{
		if reportInfo.HeadResourceId > 0 {
			headResource, tmpErr := ficc_report.GetResourceItemById(reportInfo.HeadResourceId)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			reportItem.HeadImg = headResource.ImgURL
			reportItem.HeadStyle = headResource.Style
		}

		if reportInfo.EndResourceId > 0 {
			endResource, tmpErr := ficc_report.GetResourceItemById(reportInfo.EndResourceId)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			reportItem.EndImg = endResource.ImgURL
			reportItem.EndStyle = endResource.Style
		}
	}

	if reportInfo.VideoName == "" && reportInfo.VideoUrl != "" {
		reportItem.VideoName = reportInfo.Title
	}
	reportItem.VideoSize = reportInfo.VideoSize
	reportItem.VideoPlaySeconds = reportInfo.VideoPlaySeconds
	reportItem.Author = reportInfo.Author
	// 分享背景图取二级分类配图, 二级没有配图时使用一级配图, 一级也没有使用默认图
	reportItem.ShareBgImg = utils.DEFAULT_REPORT_SHARE_BG_IMG
	secondClassify, e := ficc_report.GetByClassifyId(reportInfo.ClassifyIdSecond)
	if e != nil {
		err = errors.New("报告二级分类有误")
		return
	}
	if secondClassify.YbShareBgImg != "" {
		reportItem.ShareBgImg = secondClassify.YbShareBgImg
	} else {
		if firstClassify.YbShareBgImg != "" {
			reportItem.ShareBgImg = firstClassify.YbShareBgImg
		}
	}
	var reportTypeList []*ficc_report.ReportChapterListItem

	if reportInfo.HasChapter == 1 {
		//（晨报和周报的banner图）
		if reportInfo.ClassifyNameFirst == "晨报" {
			reportItem.BannerUrl = utils.ALIYUN_YBIMG_HOST + "report_banner_day.jpg"
		} else {
			reportItem.BannerUrl = utils.ALIYUN_YBIMG_HOST + "report_banner_week.jpg"
		}

		// 如果还没有配置banner图，则取晨报的
		if reportItem.BannerUrl == `` {
			reportItem.BannerUrl = utils.ALIYUN_YBIMG_HOST + "report_banner_day.jpg"
		}

		if authOk {
			reportTypeList, err = GetChapterListByReportChapterIdList(reportInfo.ClassifyNameFirst, reportInfo.Id, reportChapterIdList)
			if err != nil {
				return
			}
		}
	} else {
		// 音频播放条图片用分类图片
		//reportItem.VideoImg = utils.HZ_DEFAULT_AVATAR
		//permissionIds, tmpErr := chart_permission_search_key_word_mapping.GetChartPermissionIdsByKeyWord(reportInfo.ClassifyIdSecond)
		//if tmpErr != nil {
		//	errMsg = tmpErr.Error()
		//	err = errors.New("查询报告权限失败")
		//	return
		//}
		//if len(permissionIds) > 0 {
		//	chartPermission, tmpErr := chart_permission.GetListByIds(permissionIds)
		//	if tmpErr != nil {
		//		errMsg = tmpErr.Error()
		//		err = errors.New("查询品种信息失败")
		//		return
		//	}
		//	lenChart := len(chartPermission)
		//	for i := 0; i < lenChart; i++ {
		//		if chartPermission[i].YbImgUrl != "" {
		//			reportItem.VideoImg = utils.ALIYUN_YBIMG_HOST + chartPermission[i].YbImgUrl
		//			break
		//		}
		//	}
		//}
	}
	//如果有权限则展示content
	if authOk {
		reportItem.Content = HandleReportContent(html.UnescapeString(reportInfo.Content), "add", map[string]string{})
		reportItem.VideoUrl = reportInfo.VideoUrl
	}

	if userinfo.UserId == 0 {
		reportItem.Content = utils.InterceptHtmlLength(reportInfo.Content, 200)
	}

	reportDetail.ReportInfo = reportItem
	reportDetail.ReportChapterList = reportTypeList
	//reportDetail.PermissionCheck = &permissionCheckInfo
	reportDetail.AuthOk = authOk
	//reportDetail.LikeNum = likeNum
	//reportDetail.LikeEnabled = likeEnabled
	reportDetail.ReportShowType = int(firstClassify.ShowType)
	reportDetail.ReportDetailShowType = int(minClassify.ReportDetailShowType)

	// 如果分类配置是列表展示，那么就移除content内容
	if minClassify.ReportDetailShowType == 2 {
		for _, v := range reportTypeList {
			v.Content = ``
		}
	} else {
		for _, v := range reportTypeList {
			v.Content = html.UnescapeString(v.Content)
		}
	}
	return
}

// CheckWeekReportPermission
// @Description: 验证周报的权限（并获取拥有权限的章节id列表）
// @author: Roc
// @datetime 2024-06-24 11:06:52
// @param userInfo user.UserInfo
// @param reportId int
// @param productAuthOk bool
// @return authOk bool
// @return permissionCheckInfo response.PermissionCheckInfo
// @return validTypeIds []int 分类关联的章节类型ID列表
// @return reportChapterIdList []int 并获取拥有权限的章节id列表
// @return err error
func CheckWeekReportPermission(userInfo *models.WxUserItem, reportId int, productAuthOk bool) (authOk bool, permissionCheckInfo ficc_report.PermissionCheckInfo, validTypeIds, reportChapterIdList []int, err error) {
	var permissionIds []int
	//var validPermissionIds []int //最后允许显示的章节

	// 当前报告的品种与章节列表的map
	permissionChapterList := make(map[int][]int)
	permissionIdMap := make(map[int]bool)
	typeIdMap := make(map[int]bool)
	reportChapterIdMap := make(map[int]bool)
	if productAuthOk {
		reportChapterMappingList, e := ficc_report.GetReportChapterPermissionMappingItemListByReportId(reportId)
		if e != nil && e.Error() != utils.ErrNoRow() {
			err = errors.New(e.Error())
			return
		}
		for _, v := range reportChapterMappingList {
			if _, ok := permissionIdMap[v.ChartPermissionId]; !ok {
				permissionIdMap[v.ChartPermissionId] = true
				permissionIds = append(permissionIds, v.ChartPermissionId)
			}
			if _, ok := typeIdMap[v.TypeId]; !ok {
				typeIdMap[v.TypeId] = true
				validTypeIds = append(validTypeIds, v.TypeId)
			}

			tmpList, ok := permissionChapterList[v.ChartPermissionId]
			if !ok {
				tmpList = make([]int, 0)
			}

			permissionChapterList[v.ChartPermissionId] = append(tmpList, v.ReportChapterId)
			if _, ok := reportChapterIdMap[v.ReportChapterId]; !ok {
				reportChapterIdMap[v.ReportChapterId] = true
				reportChapterIdList = append(reportChapterIdList, v.ReportChapterId) //走权益的校验权限，到这里的权限都可以用
			}
		}
	}

	return
}

// GetChapterListByReportChapterIdList
// @Description: 根据报告获取章节列表
// @author: Roc
// @datetime 2024-06-24 11:23:36
// @param classifyNameFirst string
// @param reportId int
// @param reportChapterIdList []int
// @param reportCreateTime time.Time
// @return reportTypeList response.ReportChapterList
// @return err error
func GetChapterListByReportChapterIdList(classifyNameFirst string, reportId int, reportChapterIdList []int) (reportTypeList ficc_report.ReportChapterList, err error) {
	var errMsg string
	defer func() {
		if err != nil {
			go utils.SendAlarmMsg(fmt.Sprintf("GetChapterListByReport: err:%s， errMsg:%s", err.Error(), errMsg), 2)
		}
	}()
	//查询有效的章节
	typeList, e := ficc_report.GetEffectTypes()
	if e != nil {

		err = errors.New("章节类型查询出错" + e.Error())
		return
	}
	if len(typeList) == 0 {
		err = errors.New("无有效的章节")
		return
	}

	typeMap := make(map[uint64]*ficc_report.ReportChapterType)
	for _, v := range typeList {
		typeMap[v.ReportChapterTypeId] = v
	}

	var chapterList []*ficc_report.ReportChapter
	if len(reportChapterIdList) > 0 {
		//获取所有当前研报有权限的章节
		chapterList, e = ficc_report.GetListByChapterIds(reportChapterIdList)
	} else {
		// 获取所有报告章节
		chapterList, e = ficc_report.GetListByReportId(reportId, classifyNameFirst)
	}
	if e != nil && e.Error() != utils.ErrNoRow() {
		err = errors.New("章节查询出错" + e.Error())
		return
	}
	if len(chapterList) == 0 {
		err = errors.New("无有效章节")
		return
	}

	for _, item := range chapterList {
		typeItem, ok1 := typeMap[uint64(item.TypeId)]
		// 如果是配置的章节，那么就需要判断是否禁用，如果禁用，则不展示
		if item.TypeId > 0 && !ok1 {
			continue
		}

		temp := new(ficc_report.ReportChapterListItem)
		temp.ReportChapterId = item.ReportChapterId
		temp.TypeId = item.TypeId
		temp.TypeName = item.TypeName
		temp.Title = item.Title
		temp.Trend = item.Trend
		temp.ReportId = item.ReportId
		temp.Sort = item.Sort
		temp.PublishTime = item.PublishTime
		temp.VideoUrl = item.VideoUrl
		temp.VideoName = item.VideoName
		temp.VideoPlaySeconds = item.VideoPlaySeconds
		temp.VideoSize = item.VideoSize
		temp.Content = item.Content

		// 系统配置的参数，只有配置的章节类型，才能赋值
		if typeItem != nil {
			temp.ReportChapterTypeKey = typeItem.ReportChapterTypeKey
			temp.ReportChapterTypeName = typeItem.ReportChapterTypeName
			temp.ReportChapterTypeThumb = typeItem.YbIconUrl
		}

		reportTypeList = append(reportTypeList, temp)
	}
	//if len(reportTypeList) > 0 {
	//	sort.Sort(reportTypeList)
	//}
	return
}

//func init() {
//	var condition string
//	var pars []interface{}
//	condition += ` AND  report_id > 0 AND body = ''   `
//	articleList, e := models.GetCygxCygxArticleList(condition, pars, 0, 99)
//	if e != nil {
//		fmt.Println(e)
//		return
//	}
//	for k, v := range articleList {
//		fmt.Println("kkk", k)
//		content := GetReportChapterPermissionMappingItemListByReportId(v.ReportId, "晨会纪要")
//		e = models.ModifyArticleFiccBodyByreport_id(v.ReportId, content)
//		if e != nil {
//			fmt.Println(e)
//			return
//		}
//	}
//	//UpdateFICCReportResourceData(5542)
//}

// 根据ID获取FICC研报章节内容详情
func GetReportChapterPermissionMappingItemListByReportId(reportId int, classifyNameFirst string) (content string) {
	var err error
	defer func() {
		if err != nil {
			fmt.Println(err)
			go utils.SendAlarmMsg(fmt.Sprint("根据ID获取FICC研报章节内容详情失败 ，GetReportChapterPermissionMappingItemListByReportId err：", err.Error()), 2)
		}
	}()
	chapterList, e := ficc_report.GetListByReportId(reportId, classifyNameFirst)
	if e != nil {
		err = errors.New("GetListByReportId, Err: " + e.Error())
		return
	}
	for _, v := range chapterList {
		bodyText, _ := GetReportContentTextSubNew(v.Content)
		content += bodyText
	}
	fmt.Println(content)
	return
}

// 获取FICC研报到查研观向数据库中
func GetFiccRreportToCygxArticle(cont context.Context) (err error) {
	//func GetFiccRreportToCygxArticle() (err error) {
	defer func() {
		if err != nil {
			fmt.Println(err)
			go utils.SendAlarmMsg(fmt.Sprint("获取FICC研报到查研观向数据库中定时任务失败 ，err：", err.Error()), 2)
		}
	}()
	var condition string
	var pars []interface{}
	modifyTime := time.Now().Add(-10 * time.Minute)
	condition = `  AND modify_time >= ?   `
	pars = append(pars, modifyTime)
	reportList, e := ficc_report.GetFiccRreportToCygxArticle(condition, pars)
	if e != nil {
		err = errors.New("GetFiccRreportToCygxArticle, Err: " + e.Error())
		return
	}
	fmt.Println(len(reportList))
	//if len(reportList) == 0 {
	//	return
	//}
	//获取研报的匹配关系
	conf, e := models.GetConfigByCode(utils.GET_FICC_REPORT_SET)
	if e != nil {
		err = errors.New("GetConfigByCode, Err: " + e.Error())
		return
	}
	if conf.ConfigValue == "" {
		err = errors.New("同步FICC研报的规则配置值有误")
		return
	}
	listFiccSet := new(ficc_report.GetReporteSetListResp)
	if e = json.Unmarshal([]byte(conf.ConfigValue), &listFiccSet); e != nil {
		err = errors.New("同步FICC研报的规则配置值解析失败 Err: " + e.Error())
		return
	}

	if len(reportList) > 0 {
		var reportIds []int
		for _, v := range reportList {
			reportIds = append(reportIds, v.Id)
		}
		listFiccReport, e := models.GetCygxCygxArticleListByReportIds(reportIds)
		if e != nil {
			err = errors.New("GetCygxCygxArticleListByReportIds, Err: " + e.Error())
			return
		}
		mapFiccReport := make(map[int]int)
		for _, v := range listFiccReport {
			mapFiccReport[v.ReportId] = v.ArticleId
		}

		//量不大，先这么写吧
		for _, v := range reportList {
			time.Sleep(1 * time.Millisecond) // 延时一秒
			item := new(models.CygxArticle)
			item.ReportId = v.Id
			item.PublishDate = v.PublishTime.Format(utils.FormatDateTime)
			item.Title = v.Title
			if v.ClassifyNameFirst == "晨会纪要" && v.ClassifyNameSecond == "晨会纪要" {
				item.Title = "FICC/周期品晨会纪要"
			}
			item.CategoryName = utils.ZHOU_QI_NAME

			if v.Content == "" {
				item.Body = GetReportChapterPermissionMappingItemListByReportId(v.Id, v.ClassifyNameFirst)
			} else {
				item.Body = v.Content
			}
			item.Abstract = v.Abstract
			item.FieldName = v.ClassifyNameSecond
			item.CreateDate = time.Now().Format(utils.FormatDate)
			item.PublishStatus = 1
			item.IsReport = 1
			item.IsClass = 1
			item.CreateTime = time.Now()
			item.ChartPermissionName = utils.ZHOU_QI_NAME
			item.ChartPermissionId = utils.ZHOU_QI_ID

			var haveSet bool
			for _, vSet := range listFiccSet.List {
				if v.ClassifyNameFirst == vSet.ClassifyNameFirst && v.ClassifyNameSecond == vSet.ClassifyNameSecond {
					haveSet = true
					item.SubCategoryName = v.ClassifyNameSecond
					item.MatchTypeName = v.ClassifyNameSecond
					continue
				}
			}
			if !haveSet {
				continue
			}

			detailCategory, detailCategoryErr := models.GetCygxReportMappingCelueDetailByZhoQiCategoryName(item.SubCategoryName)
			if detailCategoryErr != nil {
				continue
			}
			item.CategoryId = detailCategory.CategoryId
			item.CategoryIdTwo = detailCategory.CategoryId
			var articleIdMax int
			//如果不存在就新增
			if mapFiccReport[v.Id] == 0 {
				maxArticleIdArticleInfo, e := models.GetMaxArticleIdInfo()
				if e != nil {
					err = errors.New("GetMaxArticleIdInfo, Err: " + e.Error())
					return
				}
				articleIdMax = maxArticleIdArticleInfo.ArticleId + 1
				item.ArticleIdMd5 = utils.MD5(strconv.Itoa(articleIdMax))
				item.ArticleId = articleIdMax
				_, e = models.AddCygxArticles(item)
				if e != nil {
					err = errors.New("AddCygxArticles, Err: " + e.Error())
					return
				}
			} else {
				articleIdMax = mapFiccReport[v.Id]
				item.ArticleId = mapFiccReport[v.Id]
				updateParams := make(map[string]interface{})
				updateParams["Title"] = item.Title
				updateParams["PublishDate"] = item.PublishDate
				updateParams["Body"] = item.Body
				updateParams["Abstract"] = item.Abstract
				updateParams["PublishStatus"] = item.PublishStatus
				updateParams["SubCategoryName"] = item.SubCategoryName
				updateParams["MatchTypeName"] = item.MatchTypeName
				updateParams["FieldName"] = item.FieldName
				updateParams["CategoryId"] = item.CategoryId
				updateParams["CategoryIdTwo"] = item.CategoryIdTwo
				whereParam := map[string]interface{}{"article_id": item.ArticleId}
				err = models.UpdateByExpr(models.CygxArticle{}, whereParam, updateParams)
				if err != nil {
					fmt.Println("UpdateByExpr Err:" + err.Error())
					return err
				}
			}
			UpdateFICCReportResourceData(v.Id, listFiccSet)

			AddCygxReportMappingCategoryGroupByArticleId(articleIdMax)
			UpdateCygxZhouqiArticleMapTime(item.FieldName) //更新周期对应分类下所管理文章的更新时间
		}
	}

	//获取已经同步到查研的FICC研报 对比，如果FICC研报已经取消发布，查研也做对应的删除
	listCygxFiccReport, e := models.GetCygxCygxArticleFiccReportList()
	if e != nil {
		err = errors.New("GetCygxCygxArticleFiccReportList, Err: " + e.Error())
		return
	}
	var cygxFiccReportIds []int
	for _, v := range listCygxFiccReport {
		if v.PublishStatus == 1 {
			cygxFiccReportIds = append(cygxFiccReportIds, v.ReportId)
		}
	}
	lenArr := len(cygxFiccReportIds)
	if lenArr == 0 {
		return
	}
	reportByHandList, e := ficc_report.GetCygxFiccReportByHandList() // 手动同步过来的报告
	if e != nil {
		err = errors.New("GetCygxFiccReportByHandList, Err: " + e.Error())
		return
	}
	ficcReporIdsHand := make(map[int]bool) // Ficc 研报手动同步过来的报告ID
	for _, v := range reportByHandList {
		ficcReporIdsHand[v.FiccReportId] = true
	}

	condition = ` AND id IN (` + utils.GetOrmInReplace(lenArr) + `) `
	pars = make([]interface{}, 0)
	pars = append(pars, cygxFiccReportIds)
	ficcReportListPush, e := ficc_report.GetFiccRreportToCygxArticle(condition, pars)
	if e != nil {
		err = errors.New("GetFiccRreportToCygxArticle, Err: " + e.Error())
		return
	}
	var removeficcReporIds []int           // 需要移除的报告ID
	ficcReporIdsPush := make(map[int]bool) // Ficc 研报还存在的报告ID
	for _, v := range ficcReportListPush {
		ficcReporIdsPush[v.Id] = true
	}

	for _, v := range listCygxFiccReport {
		if !ficcReporIdsPush[v.ReportId] && !ficcReporIdsHand[v.ReportId] { // 手动同步过来的报告不做删除处理
			removeficcReporIds = append(removeficcReporIds, v.ReportId)
		}
	}
	if len(removeficcReporIds) > 0 {
		e = models.HideCygxResourceDataFiccReport(removeficcReporIds)
		if e != nil {
			err = errors.New("HideCygxResourceDataFiccReport, Err: " + e.Error())
			return
		}
	}

	fmt.Println("end")
	return
}

// 根据用户信息，获取跳转研报小程序详情信息
func GetFiccReportXcxItem(user *models.WxUserItem) (itemSourceResp *models.CygxResourceDataResp) {

	var err error
	defer func() {
		if err != nil {
			fmt.Println(err)
			go utils.SendAlarmMsg(fmt.Sprint("根据用户信息，获取跳转研报小程序详情信息失败 GetFiccReportXcxItem ，err：", err.Error(), "UserId:", user.UserId), 2)
		}
	}()

	deUserId := utils.DesBase64Encrypt([]byte(strconv.Itoa(user.UserId)))

	itemSource := new(models.CygxResourceDataResp)
	itemSource.Source = utils.CYGX_OBJ_FICC_REPORT_XCX

	itemResp := new(models.FiccReportXcx)
	itemResp.Source = utils.CYGX_OBJ_FICC_REPORT_XCX
	itemResp.Title = "每日原油播报"
	itemResp.SecondTitle = "欧美市场隔夜复盘"
	itemResp.ImgUrl = utils.FICC_REPORT_ICO_HOME
	itemResp.Mobile = user.Mobile
	itemResp.SellerMobile = ""
	itemResp.SellerName = ""
	itemResp.Appid = utils.FICC_REPORT_APPID
	itemResp.SourceUrl = "pages/voice/voice?thirdCode="
	itemResp.ThirdCode = string(deUserId)

	//var hasPermission int
	var hasPersion bool
	if user.CompanyId > 1 {
		companyPermission, e := models.GetCompanyPermission(user.CompanyId)
		if e != nil {
			err = errors.New("获取用户权限信息失败" + e.Error())
			return
		}
		if companyPermission != "" {
			slice := strings.Split(companyPermission, ",")
			if utils.InArrayByStr(slice, "周期") {
				hasPersion = true
			}
		}
	}
	var hasPermission int
	var e error
	if hasPersion {
		hasPermission = 1
	} else {
		if user.UserId == 0 {
			hasPermission = 1
		} else {
			itemResp.HasPermission, itemResp.SellerName, itemResp.SellerMobile, _, err = GetUserHasPermissionArticle(user)
			if err != nil {
				return
			}
			hasPermission, e = GetUserPermissionCode(user.UserId, user.CompanyId)
			if e != nil {
				err = errors.New("GetUserPermissionCode")
				return
			}
			itemResp.SellerName, itemResp.SellerMobile, _ = GetSellerName(user)
		}
	}

	itemResp.HasPermission = hasPermission
	itemSource.FiccReportXcx = itemResp
	itemSourceResp = itemSource
	return
}

//func init() {
//	strslice := []string{"晨会纪要", "煤炭", "铜行业数据点评", "石油石化", "黑色调研", "宏观G2观察", "黄金月报"}
//	for _, v := range strslice {
//		fmt.Println(v)
//		UpdateCygxZhouqiArticleMapTime(v)
//	}
//}

// UpdateCygxZhouqiArticleMapTime 更新周期对应分类下所管理文章的更新时间
func UpdateCygxZhouqiArticleMapTime(fieldName string) {
	var err error
	defer func() {
		if err != nil {
			fmt.Println("err：", err)
			go utils.SendAlarmMsg(fmt.Sprint("更新周期对应分类下所管理文章的更新时间 失败，UpdateCygxZhouqiArticleMapTime Err："+err.Error()+"fieldName", fieldName), 3)
		}
	}()

	detail, e := models.GetCygxZhouqiArticleMapByMatchTypeName(fieldName)
	if e != nil {
		err = errors.New("GetCygxZhouqiArticleMapByMatchTypeName, Err: " + err.Error())
		return
	}

	listCategory, e := models.GetCygxZhouqiArticleMapByParentId(detail.ParentId)
	if e != nil {
		err = errors.New("GetCygxZhouqiArticleMapByParentId, Err: " + err.Error())
		return
	}
	var matchTypeName = []string{}
	for _, v := range listCategory {
		matchTypeName = append(matchTypeName, v.MatchTypeName)
	}

	var condition string
	var pars []interface{}
	condition = "  AND category_name = '周期' AND field_name  IN  ('" + strings.Join(matchTypeName, "','") + "')  ORDER  BY  publish_date  DESC  "
	articleList, e := models.GetCygxCygxArticleList(condition, pars, 0, 1)
	if e != nil {
		err = errors.New("GetCygxCygxArticleList, Err: " + e.Error())
		return
	}

	//就一条数据
	for _, v := range articleList {
		e = models.UpdateCygxZhouqiArticleMapTime(v.PublishDate, detail.ParentId)
	}

	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())
		}
	}()
	if link == `` {
		return link
	}
	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
	key := fmt.Sprint(showType, `:`, code)
	if tokenMap != nil {
		if token, ok := tokenMap[key]; ok {
			// 在链接后面添加一个token值
			return link + "&authToken=" + token
		}
	}

	token, err := GeneralChartToken(showType, code)
	if err != nil {
		return link
	}
	if tokenMap != nil {
		tokenMap[key] = token
	}
	link = strings.Replace(link, "?code="+code, "?code="+code+"&authToken="+token, -1)
	// 在链接后面添加一个token值
	return link
}

type GeneralChartTokenReq struct {
	Appid      string `description:"APPID" json:"appid"`
	UniqueCode string `description:"图表code" json:"unique_code"`
	Source     string `description:"来源，图表：chart，表格：table" json:"source"`
}

type HzOpenApiResponse struct {
	Code   int    `json:"code"`
	Data   string `json:"data"`
	Msg    string `json:"msg"`
	ErrMsg string `json:"err_msg"`
}

// GeneralChartToken
func GeneralChartToken(source, uniqueCode string) (token string, err error) {
	defer func() {
		if err != nil {
			fmt.Println("err：", err)
			go utils.SendAlarmMsg(fmt.Sprint("GeneralChartToken 失败，GeneralChartToken Err："+err.Error()+"uniqueCode", uniqueCode), 3)
		}
	}()
	postData := make(map[string]string)
	postData["appid"] = utils.CLPT_APPID
	postData["nonce_str"] = utils.GetRandDigit(10)
	postData["timestamp"] = fmt.Sprint(time.Now().Unix())
	postData["unique_code"] = uniqueCode
	postData["source"] = source

	sign, e := getSign(postData)
	if e != nil {
		fmt.Println(e)
		err = errors.New("getSign, Err: " + e.Error())
		return
	}
	postData["sign"] = sign

	url := utils.HZ_OPEN_API_URL + "api/chart/general_token"
	method := "POST"
	data, e := json.Marshal(postData)
	if e != nil {
		err = errors.New("data json marshal err: " + e.Error())
		return
	}
	payload := strings.NewReader(string(data))
	client := &http.Client{}
	req, e := http.NewRequest(method, url, payload)
	if e != nil {
		err = errors.New(" http.NewRequest err: " + e.Error())
		return
	}
	req.Header.Add("Content-Type", "application/json")

	res, e := client.Do(req)
	if e != nil {
		err = errors.New(" client.Do err: " + e.Error())
		return
	}
	defer res.Body.Close()
	var response *HzOpenApiResponse
	body, e := ioutil.ReadAll(res.Body)
	if e != nil {
		err = errors.New("  ioutil.ReadAll: " + e.Error())
		return
	}
	e = json.Unmarshal(body, &response)
	if e != nil {
		err = errors.New("json.Unmarshal " + e.Error())
		return
	}
	token = response.Data
	return
}

// 请求参数签名校验
func getSign(postData map[string]string) (sign string, err error) {
	appid := postData["appid"]
	if appid == "" {
		err = errors.New("参数异常，缺少appid")
		return
	}
	openApiUserInfo, tmpErr := models.GetByAppid(appid)
	if tmpErr != nil {
		if tmpErr.Error() == utils.ErrNoRow() {
			err = errors.New("appid异常，请联系管理员")
		} else {
			err = errors.New("系统异常，请联系管理员")
		}
		return
	}

	if openApiUserInfo == nil {
		err = errors.New("系统异常，请联系管理员")
		return
	}

	if postData["nonce_str"] == "" {
		err = errors.New("参数异常，缺少随机字符串")
		return
	}
	if postData["timestamp"] == "" {
		err = errors.New("参数异常，缺少时间戳")
		return
	} else {
		timeUnix := time.Now().Unix() //当前格林威治时间，int64类型
		//将接口传入的时间做转换
		timestamp, timeErr := strconv.ParseInt(postData["timestamp"], 10, 64)
		if timeErr != nil {
			err = errors.New("参数异常，时间戳格式异常")
			return
		}
		if math.Abs(float64(timeUnix-timestamp)) > 300 {
			err = errors.New("当前时间异常，请调整设备时间与北京时间一致")
			return
		}
	}

	//先取出除sign外的所有的提交的参数key
	var keys []string
	for k := range postData {
		if k != "sign" {
			keys = append(keys, k)
		}
	}

	//1,根据参数名称的ASCII码表的顺序排序
	sort.Strings(keys)

	//2 根据排序后的参数名称，取出对应的值，并拼接字符串
	var signStr string
	for _, v := range keys {
		signStr += v + "=" + postData[v] + "&"
	}
	sign = strings.ToUpper(fmt.Sprintf("%x", md5.Sum([]byte(signStr+"secret="+openApiUserInfo.Secret))))

	return
}
