package services

import (
	"encoding/json"
	"errors"
	"eta/eta_api/models"
	"eta/eta_api/models/system"
	"eta/eta_api/services/alarm_msg"
	"eta/eta_api/utils"
	"fmt"
	"html"
	"strconv"
	"strings"
	"time"
)

// CreateNewEnglishReport 生成英文研报
func CreateNewEnglishReport(req models.AddEnglishReportReq, adminInfo *system.Admin) (newReportId int64, reportCode string, err error) {
	var contentSub string
	if req.Content != "" {
		content, e := FilterReportContentBr(req.Content)
		if e != nil {
			err = errors.New("内容去除前后空格失败, Err: " + e.Error())
			return
		}
		req.Content = content

		contentSub, e = GetReportContentSub(req.Content)
		if e != nil {
			go alarm_msg.SendAlarmMsg("ContentSub 失败，Err:"+e.Error(), 3)
			err = errors.New("获取报告内容前几段失败, Err: " + e.Error())
			return
		}
	}
	maxStage, e := models.GetEnglishReportStage(req.ClassifyIdFirst, req.ClassifyIdSecond)
	if e != nil {
		err = errors.New("期数获取失败, Err: " + e.Error())
		return
	}

	item := new(models.EnglishReport)
	item.AddType = req.AddType
	item.ClassifyIdFirst = req.ClassifyIdFirst
	item.ClassifyNameFirst = req.ClassifyNameFirst
	item.ClassifyIdSecond = req.ClassifyIdSecond
	item.ClassifyNameSecond = req.ClassifyNameSecond
	item.Title = req.Title
	item.Abstract = req.Abstract
	item.Author = req.Author
	item.Frequency = req.Frequency
	item.State = req.State
	item.Content = html.EscapeString(req.Content)
	item.Stage = maxStage + 1
	item.ContentSub = html.EscapeString(contentSub)
	item.CreateTime = req.CreateTime
	item.ModifyTime = time.Now()
	item.AdminId = adminInfo.AdminId
	item.AdminRealName = adminInfo.RealName
	newReportId, e = models.AddEnglishReport(item)
	if e != nil {
		err = errors.New("新增报告失败, Err: " + e.Error())
		return
	}
	reportCode = utils.MD5(strconv.Itoa(int(newReportId)))
	//修改唯一编码
	{
		go models.ModifyEnglishReportCode(newReportId, reportCode)
	}
	return
}

// IEnglishEmailSend 英文研报-邮件推送接口
type IEnglishEmailSend interface {
	NewClient() (err error)
	SendEmail(item *EnglishReportSendEmailRequest) (ok bool, result string, err error)
	BatchSendEmail(list []*EnglishReportSendEmailRequest) (results []*EnglishReportSendEmailResult, err error)
}

// EnglishReportSendEmailRequest 英文研报-推送邮件请求体
type EnglishReportSendEmailRequest struct {
	ReportId        int                           `description:"英文报告ID"`
	EmailId         int                           `description:"邮箱ID"`
	Email           string                        `description:"邮箱地址"`
	Subject         string                        `description:"邮件主题"`
	FromAlias       string                        `description:"发信人昵称"`
	ReportTitle     string                        `description:"报告标题"`
	ReportAbstract  string                        `description:"报告摘要"`
	ReportContent   string                        `description:"报告内容"`
	ReportShareLink string                        `description:"报告分享链接"`
	ReportTime      string                        `description:"报告时间"`
	HtmlBody        string                        `description:"模板内容主体"`
	EmailLog        *models.EnglishReportEmailLog `description:"日志记录"`
}

// EnglishReportSendEmailResult 英文研报-推送邮件响应体
type EnglishReportSendEmailResult struct {
	ReportId   int    `description:"英文报告ID"`
	EmailId    int    `description:"邮箱ID"`
	Email      string `description:"邮箱地址"`
	Ok         bool   `description:"是否推送成功"`
	SendData   string `description:"请求数据-JSON"`
	ResultData string `description:"推送结果-JSON"`
	Source     int    `description:"服务来源：1-阿里云；2-腾讯云"`
}

// BatchSendAliEnglishReportEmail 批量推送英文研报邮件
func BatchSendAliEnglishReportEmail(list []*EnglishReportSendEmailRequest) (err error) {
	defer func() {
		if err != nil {
			tips := fmt.Sprintf("阿里云群发英文研报邮件失败 err: %s\n", err.Error())
			utils.FileLog.Info(tips)
			fmt.Println(tips)
			go alarm_msg.SendAlarmMsg(tips, 3)
		}
	}()
	if len(list) == 0 {
		return
	}
	requestMap := make(map[int]*EnglishReportSendEmailRequest, 0)
	for _, v := range list {
		requestMap[v.EmailId] = v
	}

	// 请求阿里云接口批量推送
	aliEmail := new(AliyunEmail)
	resultList, e := aliEmail.BatchSendEmail(list)
	if e != nil {
		err = e
		return
	}

	// 返回的结果更新日志
	resendList := make([]*EnglishReportSendEmailRequest, 0)
	failLogIds := make([]int, 0)
	updateLogs := make([]*models.EnglishReportEmailLog, 0)
	for _, v := range resultList {
		req := requestMap[v.EmailId]
		if req == nil {
			continue
		}
		l := req.EmailLog
		if l == nil {
			continue
		}

		//l.SendData = v.SendData
		l.Result = v.ResultData
		if v.Ok {
			l.SendStatus = models.EnglishReportEmailLogStatusSuccess
		} else {
			l.SendStatus = models.EnglishReportEmailLogStatusFail
			failLogIds = append(failLogIds, l.Id)
			if requestMap[v.EmailId] != nil {
				resendList = append(resendList, requestMap[v.EmailId])
			}
			// 取出错误信息
			r := new(AliyunEmailResult)
			if e = json.Unmarshal([]byte(v.ResultData), &r); e != nil {
				continue
			}
			rd := new(AliyunEmailResultData)
			res := strings.Replace(r.Data, `\`, ``, -1)
			if e = json.Unmarshal([]byte(res), &rd); e != nil {
				continue
			}
			l.ErrMsg = rd.Message
		}
		updateLogs = append(updateLogs, l)
	}

	// 更新日志
	logOb := new(models.EnglishReportEmailLog)
	if e = logOb.MultiUpdateResult(updateLogs); e != nil {
		err = fmt.Errorf("批量更新日志信息失败, Err: " + e.Error())
		return
	}

	// 推送失败的重新腾讯云, 若腾讯云也失败将不再自动重推, 用户手动去重推
	if len(resendList) > 0 && len(failLogIds) > 0 {
		hasFail, _ := ResendTencentEnglishReportEmail(resendList, failLogIds)
		//fmt.Printf("hasFail: %v", hasFail)
		// 存在发送失败则更新报告标识
		if hasFail {
			if e = models.UpdateEnglishReportEmailHasFail(list[0].ReportId); e != nil {
				err = fmt.Errorf("UpdateEnglishReportEmailHasFail err: %s", e.Error())
				return
			}
		}
	}
	return
}

// ResendTencentEnglishReportEmail 腾讯云邮件重新推送
func ResendTencentEnglishReportEmail(resendList []*EnglishReportSendEmailRequest, failLogIds []int) (hasFail bool, err error) {
	defer func() {
		if err != nil {
			hasFail = true
			tips := fmt.Sprintf("腾讯云重发英文研报邮件失败 err: %s\n", err.Error())
			utils.FileLog.Info(tips)
			fmt.Println(tips)
			go alarm_msg.SendAlarmMsg(tips, 3)
		}
	}()
	if len(resendList) == 0 || len(failLogIds) == 0 {
		return
	}

	// 标记原有日志为已删除
	if len(failLogIds) > 0 {
		if e := models.DeleteEnglishReportEmailLogByIds(failLogIds); e != nil {
			err = errors.New("删除原邮件日志失败, Err: " + e.Error())
			return
		}
	}

	// 写入新的日志
	nowTime := time.Now().Local()
	logData := make([]*models.EnglishReportEmailLog, 0)
	logMap := make(map[int]*models.EnglishReportEmailLog, 0)
	for _, v := range resendList {
		logItem := &models.EnglishReportEmailLog{
			ReportId:   v.ReportId,
			EmailId:    v.EmailId,
			Email:      v.Email,
			Source:     models.EnglishReportEmailLogSourceTencent,
			SendStatus: models.EnglishReportEmailLogStatusIng,
			CreateTime: nowTime,
		}
		logData = append(logData, logItem)
		logMap[v.EmailId] = logItem
	}
	for _, v := range logData {
		if e := v.Create(); e != nil {
			err = fmt.Errorf("写入群发邮件日志失败, err: %s", e.Error())
			return
		}
	}

	// 请求腾讯云
	tencentEmail := new(TencentEmail)
	resultList, e := tencentEmail.BatchSendEmail(resendList)
	if e != nil {
		err = e
		return
	}
	updateLogs := make([]*models.EnglishReportEmailLog, 0)
	for _, v := range resultList {
		l := logMap[v.EmailId]
		if l == nil {
			continue
		}
		l.Result = v.ResultData
		if v.Ok {
			l.SendStatus = models.EnglishReportEmailLogStatusSuccess
		} else {
			l.SendStatus = models.EnglishReportEmailLogStatusFail
			r := new(TencentEmailResult)
			if e = json.Unmarshal([]byte(v.ResultData), &r); e != nil {
				continue
			}
			l.ErrMsg = r.Message
			hasFail = true
		}
		updateLogs = append(updateLogs, l)
	}

	// 更新日志
	logOb := new(models.EnglishReportEmailLog)
	if e = logOb.MultiUpdateResult(updateLogs); e != nil {
		err = fmt.Errorf("批量更新日志信息失败, Err: " + e.Error())
		return
	}
	return
}

// UpdateEnglishReportEs 更新英文报告/章节Es
func UpdateEnglishReportEs(reportId int, publishState int) (err error) {
	if reportId <= 0 {
		return
	}
	reportInfo, err := models.GetEnglishReportById(reportId)
	if err != nil {
		return
	}
	// 新增报告ES
	esReport := &models.ElasticEnglishReportDetail{
		Id:                 strconv.Itoa(reportInfo.Id),
		ReportId:           reportInfo.Id,
		Title:              reportInfo.Title,
		Abstract:           reportInfo.Abstract,
		BodyContent:        utils.TrimHtml(html.UnescapeString(reportInfo.Content)),
		PublishTime:        reportInfo.PublishTime,
		CreateTime:         reportInfo.CreateTime,
		ReportCode:         reportInfo.ReportCode,
		PublishState:       publishState,
		Author:             reportInfo.Author,
		Frequency:          reportInfo.Frequency,
		ClassifyIdFirst:    reportInfo.ClassifyIdFirst,
		ClassifyNameFirst:  reportInfo.ClassifyNameFirst,
		ClassifyIdSecond:   reportInfo.ClassifyIdSecond,
		ClassifyNameSecond: reportInfo.ClassifyNameSecond,
		StageStr:           strconv.Itoa(reportInfo.Stage),
		Overview:           utils.TrimHtml(html.UnescapeString(reportInfo.Overview)),
		ContentSub:         utils.TrimHtml(html.UnescapeString(reportInfo.ContentSub)),
	}
	docId := fmt.Sprintf("%d", reportInfo.Id)
	if err = EsAddOrEditEnglishReport(utils.EsEnglishReportIndexName, docId, esReport); err != nil {
		return
	}
	return
}

// ModifyAllEsEnglishReportVideo 批量修改es里的英文研报信息和线上路演信息
func ModifyAllEsEnglishReportVideo() (err error) {
	reportList, err := models.GetEnglishReportByCondition("", []interface{}{})
	if err != nil {
		return
	}
	for _, reportInfo := range reportList {
		// 新增报告ES
		esReport := &models.ElasticEnglishReportDetail{
			Id:                 strconv.Itoa(reportInfo.Id),
			ReportId:           reportInfo.Id,
			Title:              reportInfo.Title,
			Abstract:           reportInfo.Abstract,
			BodyContent:        utils.TrimHtml(html.UnescapeString(reportInfo.Content)),
			PublishTime:        reportInfo.PublishTime.Format(utils.FormatDateTime),
			CreateTime:         reportInfo.CreateTime,
			ReportCode:         reportInfo.ReportCode,
			PublishState:       reportInfo.State,
			Author:             reportInfo.Author,
			Frequency:          reportInfo.Frequency,
			ClassifyIdFirst:    reportInfo.ClassifyIdFirst,
			ClassifyNameFirst:  reportInfo.ClassifyNameFirst,
			ClassifyIdSecond:   reportInfo.ClassifyIdSecond,
			ClassifyNameSecond: reportInfo.ClassifyNameSecond,
			StageStr:           strconv.Itoa(reportInfo.Stage),
			Overview:           utils.TrimHtml(html.UnescapeString(reportInfo.Overview)),
			ContentSub:         utils.TrimHtml(html.UnescapeString(reportInfo.ContentSub)),
		}
		docId := fmt.Sprintf("%d", reportInfo.Id)
		if err = EsAddOrEditEnglishReport(utils.EsEnglishReportIndexName, docId, esReport); err != nil {
			return
		}
	}

	videoList, err := models.GetEnglishVideoByCondition("", []interface{}{})
	if err != nil {
		return
	}
	for _, videoInfo := range videoList {
		// 新增报告ES
		esReport := &models.ElasticEnglishReportDetail{
			Id:                 "v" + strconv.Itoa(videoInfo.Id),
			VideoId:            videoInfo.Id,
			Title:              videoInfo.Title,
			Abstract:           videoInfo.Abstract,
			BodyContent:        "",
			PublishTime:        videoInfo.PublishTime.Format(utils.FormatDateTime),
			CreateTime:         videoInfo.CreateTime.Format(utils.FormatDateTime),
			ReportCode:         videoInfo.VideoCode,
			PublishState:       videoInfo.State,
			Author:             videoInfo.Author,
			Frequency:          "",
			ClassifyIdFirst:    videoInfo.ClassifyIdFirst,
			ClassifyNameFirst:  videoInfo.ClassifyNameFirst,
			ClassifyIdSecond:   videoInfo.ClassifyIdSecond,
			ClassifyNameSecond: videoInfo.ClassifyNameSecond,
			StageStr:           "",
			Overview:           utils.TrimHtml(html.UnescapeString(videoInfo.Overview)),
			ContentSub:         "",
		}
		docId := fmt.Sprintf("v%d", videoInfo.Id)
		if err = EsAddOrEditEnglishReport(utils.EsEnglishReportIndexName, docId, esReport); err != nil {
			return
		}
	}
	return
}

// UpdateEnglishVideoEs 更新英文线上路演Es
func UpdateEnglishVideoEs(videoId int, publishState int) (err error) {
	if videoId <= 0 {
		return
	}
	videoInfo, err := models.GetEnglishVideoById(videoId)
	if err != nil {
		return
	}
	// 新增报告ES
	esReport := &models.ElasticEnglishReportDetail{
		Id:                 "v" + strconv.Itoa(videoInfo.Id),
		VideoId:            videoInfo.Id,
		Title:              videoInfo.Title,
		Abstract:           videoInfo.Abstract,
		BodyContent:        "",
		PublishTime:        videoInfo.PublishTime,
		CreateTime:         videoInfo.CreateTime,
		ReportCode:         videoInfo.VideoCode,
		PublishState:       publishState,
		Author:             videoInfo.Author,
		Frequency:          "",
		ClassifyIdFirst:    videoInfo.ClassifyIdFirst,
		ClassifyNameFirst:  videoInfo.ClassifyNameFirst,
		ClassifyIdSecond:   videoInfo.ClassifyIdSecond,
		ClassifyNameSecond: videoInfo.ClassifyNameSecond,
		StageStr:           "",
		Overview:           utils.TrimHtml(html.UnescapeString(videoInfo.Overview)),
		ContentSub:         "",
	}
	docId := fmt.Sprintf("v%d", videoInfo.Id)
	if err = EsAddOrEditEnglishReport(utils.EsEnglishReportIndexName, docId, esReport); err != nil {
		return
	}
	return
}

func UpdateEnglishReportClassifyId(oldItem, newItem *models.EnglishClassify, classifyId int) (err error) {
	defer func() {
		if err != nil {
			go alarm_msg.SendAlarmMsg("英文报告分类改名-同步更新报告表字段及权限表关键词失败3, Err："+err.Error(), 3)
		}
	}()
	//如果二级分类变更为一级分类
	//如果二级分类更换了父级分类，则更新报告中的父级分类ID
	//如果一级分类更换了名称，则更新所有报告中的一级分类名称
	//如果二级分类更换了名称，则更新所有报告中的二级分类名称
	if oldItem.ParentId > 0 && oldItem.ParentId != newItem.ParentId {
		//二级分类下的三级分类如果有报告，则该二级分类不允许改成一级分类
		if oldItem.ParentId > 0 && oldItem.ParentId == oldItem.RootId {
			if newItem.ParentId == 0 {
				// 更新报告表分类字段
				var condition string
				var pars []interface{}

				condition += ` AND classify_id_first = ? `
				pars = append(pars, classifyId)
				count, e := models.GetEnglishReportCountByCondition(condition, pars)
				if e != nil {
					err = e
					return
				}
				if count > 0 {
					err = fmt.Errorf("该分类有关联的报告，不允许变更为一级分类")
					return
				}
			}
		} else if oldItem.ParentId > 0 && oldItem.ParentId != oldItem.RootId {
			//三级分类下如果有报告，则该三级分类不允许改成二级或或者一级分类
			if (newItem.ParentId > 0 && newItem.ParentId == newItem.RootId) || newItem.ParentId == 0 {
				// 更新报告表分类字段
				var condition string
				var pars []interface{}

				condition += ` AND classify_id_second = ? `
				pars = append(pars, classifyId)
				count, e := models.GetEnglishReportCountByCondition(condition, pars)
				if e != nil {
					err = e
					return
				}
				if count > 0 {
					err = fmt.Errorf("该分类有关联的报告，不允许变更为二级分类或者一级分类")
					return
				}
			}
		}
	}
	return
}

func UpdateEnglishVideoClassifyId(oldItem, newItem *models.EnglishClassify, classifyId int) (err error) {
	//一级分类改为二级分类
	defer func() {
		if err != nil {
			go alarm_msg.SendAlarmMsg("英文报告分类改名-同步更新报告表字段及权限表关键词失败3, Err："+err.Error(), 3)
		}
	}()
	//如果二级分类变更为一级分类
	//如果二级分类更换了父级分类，则更新报告中的父级分类ID
	//如果一级分类更换了名称，则更新所有报告中的一级分类名称
	//如果二级分类更换了名称，则更新所有报告中的二级分类名称
	if oldItem.ParentId > 0 && oldItem.ParentId != newItem.ParentId {
		//二级分类下的三级分类如果有报告，则该二级分类不允许改成一级分类
		if oldItem.ParentId > 0 && oldItem.ParentId == oldItem.RootId {
			if newItem.ParentId == 0 {
				// 更新报告表分类字段
				var condition string
				var pars []interface{}

				condition += ` AND classify_id_first = ? `
				pars = append(pars, classifyId)
				count, e := models.GetEnglishVideoListCount(condition, pars)
				if e != nil {
					err = e
					return
				}
				if count > 0 {
					err = fmt.Errorf("该分类有关联的视频，不允许变更为一级分类")
					return
				}
			}
		} else if oldItem.ParentId > 0 && oldItem.ParentId != oldItem.RootId {
			//三级分类下如果有报告，则该三级分类不允许改成二级或或者一级分类
			if (newItem.ParentId > 0 && newItem.ParentId == newItem.RootId) || newItem.ParentId == 0 {
				// 更新报告表分类字段
				var condition string
				var pars []interface{}

				condition += ` AND classify_id_second = ? `
				pars = append(pars, classifyId)
				count, e := models.GetEnglishVideoListCount(condition, pars)
				if e != nil {
					err = e
					return
				}
				if count > 0 {
					err = fmt.Errorf("该分类有关联的视频，不允许变更为二级分类或者一级分类")
					return
				}
			}
		}
	}
	return
}

// UpdateAllPublishedEnglishReportToEs 更新所有已发布的报告ES
func UpdateAllPublishedEnglishReportToEs() (err error) {
	// 获取所有已发布的报告
	var condition string
	var pars []interface{}
	condition = ` AND state IN (2, 6) `
	reportList, err := models.GetEnglishReportByCondition(condition, pars)
	count := 0
	failCount := 0
	for i := 0; i < len(reportList); i++ {
		if err = UpdateEnglishReportEs(reportList[i].Id, 2); err != nil {
			fmt.Printf("更新失败, report_id: %d, Err: %s\n", reportList[i].Id, err.Error())
			failCount += 1
		} else {
			count += 1
		}
	}
	fmt.Printf("报告总数：%d, 更新成功数: %d, 更新失败数: %d", len(reportList), count, failCount)

	return
}

func CreateEnglishReportIndex() {
	indexName := utils.EsEnglishReportIndexName
	mappingJson := `{
  "mappings": {
    "dynamic": true,
    "properties": {
        "Frequency" : {
          "type" : "text"
        },
        "ReportCode" : {
          "type" : "text"
        },
        "Author" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "BodyContent" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
"Overview" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "Abstract" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "ClassifyIdFirst" : {
          "type" : "long"
        },
        "ClassifyIdSecond" : {
          "type" : "long"
        },
        "ClassifyNameFirst" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "ClassifyNameSecond" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "PublishState" : {
          "type" : "long"
        },
        "PublishTime" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
       "CreateTime" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "ReportId" : {
          "type" : "long"
        },
        "StageStr" : {
          "type" : "text"
        },
        "Title" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
  }
}`
	EsCreateIndex(indexName, mappingJson)
}

// UpdateEnReportEditMark 更新英文研报当前更新状态
// status 枚举值 1：编辑中，0：完成编辑, 2：只做查询
func UpdateEnReportEditMark(reportId, nowUserId, status int, nowUserName, lang string) (ret models.MarkReportResp, err error) {
	//更新标记key
	key := fmt.Sprint(`crm:enReport:edit:`, reportId)
	opUserId, e := utils.Rc.RedisInt(key)
	var opUser models.MarkReportItem
	if e != nil {
		opUserInfoStr, tErr := utils.Rc.RedisString(key)
		if tErr == nil {
			tErr = json.Unmarshal([]byte(opUserInfoStr), &opUser)
			if tErr == nil {
				opUserId = opUser.AdminId
			}
		}
	}
	if opUserId > 0 && opUserId != nowUserId {
		editor := opUser.Editor
		if editor == "" {
			//查询账号的用户姓名
			otherInfo, e := system.GetSysAdminById(opUserId)
			if e != nil {
				err = fmt.Errorf("查询其他编辑者信息失败")
				return
			}
			editor = otherInfo.RealName
		}

		ret.Status = 1
		if lang == utils.EnLangVersion {
			ret.Msg = fmt.Sprintf("%s is currently editing the report", editor)
		} else {
			ret.Msg = fmt.Sprintf("当前%s正在编辑报告", editor)
		}
		ret.Editor = editor
		return
	}
	if status == 1 {
		nowUser := &models.MarkReportItem{AdminId: nowUserId, Editor: nowUserName}
		bt, e := json.Marshal(nowUser)
		if e != nil {
			err = fmt.Errorf("格式化编辑者信息失败")
			return
		}
		if opUserId > 0 {
			utils.Rc.Do("SETEX", key, int64(180), string(bt)) //3分钟缓存
		} else {
			utils.Rc.SetNX(key, string(bt), time.Second*60*3) //3分钟缓存
		}
	} else if status == 0 {
		//清除编辑缓存
		_ = utils.Rc.Delete(key)
	}
	return
}

// 英文策略报告一键同步功能
func EnglishPolicyReportSync(id int, adminInfo *system.Admin) (err error, errMsg string) {
	//查询报告是否存在
	policyReport, err := models.GetEnglishPolicyReportById(id)
	if err != nil {
		if err.Error() == utils.ErrNoRow() {
			err = fmt.Errorf("报告不存在！")
			return
		}
		errMsg = "获取报告信息失败,Err:" + err.Error()
		err = fmt.Errorf("获取报告信息失败")
		return
	}
	//判断报告是否已同步
	if policyReport.State == 2 {
		err = fmt.Errorf("报告已同步，无需重复同步")
		return
	}
	//新增英文研报
	classifyNameFirst := "Macro"
	classifySecondName := "China A-share Daily Check-in"

	// 根据分类名称查询分类ID
	classifyInfo, err := models.GetEnglishClassifyByClassifyNameAndParentName(classifyNameFirst, classifySecondName)
	if err != nil {
		if err.Error() == utils.ErrNoRow() {
			err = fmt.Errorf("报告分类不存在！")
			return
		}
		errMsg = "获取报告分类失败,Err:" + err.Error()
		err = fmt.Errorf("获取报告分类失败")
		return
	}
	// 获取期数
	maxStage, err := models.GetEnglishReportStage(classifyInfo.ParentId, classifyInfo.Id)
	if err != nil {
		errMsg = "期数获取失败,Err:" + err.Error()
		err = fmt.Errorf("期数获取失败")
		return
	}
	var contentSub string
	if policyReport.Content != "" {
		contentSub, err = GetReportContentSub(policyReport.Content)
		if err != nil {
			go alarm_msg.SendAlarmMsg("策略报告 一键同步 ContentSub 失败，Err:"+err.Error(), 3)
			//utils.SendEmail(utils.APPNAME+"失败提醒", "解析 ContentSub 失败，Err:"+err.Error(), utils.EmailSendToUsers)
		}
	}

	item := new(models.EnglishReport)
	item.AddType = 1
	item.ClassifyIdFirst = classifyInfo.ParentId
	item.ClassifyNameFirst = classifyInfo.ParentClassifyName
	item.ClassifyIdSecond = classifyInfo.Id
	item.ClassifyNameSecond = classifyInfo.ClassifyName
	item.Title = "China A-share Daily Check-in"
	item.Abstract = "China A-share market and economic data review"
	item.Author = "Horizon Insights FICC Team"
	item.Frequency = policyReport.Frequency
	item.State = 1
	item.Content = policyReport.Content
	item.Stage = maxStage + 1
	item.ContentSub = html.EscapeString(contentSub)
	item.CreateTime = time.Now().Format(utils.FormatDateTime)
	item.ModifyTime = time.Now()
	item.Overview = policyReport.Abstract
	item.KeyTakeaways = policyReport.KeyTakeaways
	item.FromReportId = policyReport.Id
	item.AdminId = adminInfo.AdminId
	item.AdminRealName = adminInfo.RealName
	newReportId, err := models.AddEnglishReport(item)
	if err != nil {
		errMsg = "保存研报失败,Err:" + err.Error()
		err = fmt.Errorf("保存研报失败")
		return
	}
	reportCode := utils.MD5(strconv.Itoa(int(newReportId)))
	//修改唯一编码
	{
		go models.ModifyEnglishReportCode(newReportId, reportCode)
	}
	//更新策略报告状态为已同步
	if err = models.SyncEnglishPolicyReportById(policyReport.Id, int(newReportId)); err != nil {
		errMsg = "更新策略报告失败,Err:" + err.Error()
		err = fmt.Errorf("更新策略报告失败")
		return
	}
	return
}

// 英文策略报告批量同步功能
func MultiEnglishPolicyReportSync() (err error, errMsg string) {
	//查询发布时间是当天的所有未同步的报告，并更新到英文研报
	condition := ""
	var pars []interface{}
	//startDate := time.Now().Format(utils.FormatDate)
	startDate := time.Now().AddDate(0, -1, 0).Format(utils.FormatDate)
	condition += ` AND publish_time >= ? AND state = 1 AND (content !="" AND content is not null)`
	pars = append(pars, startDate)
	policyReports, err := models.GetEnglishPolicyReportByCondition(condition, pars)
	if err != nil {
		errMsg = "查询英文策略报告列表接口失败"
		return
	}
	if len(policyReports) == 0 {
		return
	}
	//新增英文研报
	classifyNameFirst := "Equity"
	classifySecondName := "A-share Daily"

	// 根据分类名称查询分类ID
	classifyInfo, err := models.GetEnglishClassifyByClassifyNameAndParentName(classifyNameFirst, classifySecondName)
	if err != nil {
		if err.Error() == utils.ErrNoRow() {
			err = fmt.Errorf("报告分类不存在！")
			return
		}
		errMsg = "获取报告分类失败,Err:" + err.Error()
		err = fmt.Errorf("获取报告分类失败")
		return
	}
	// 获取期数
	maxStage, err := models.GetEnglishReportStage(classifyInfo.ParentId, classifyInfo.Id)
	if err != nil {
		errMsg = "期数获取失败,Err:" + err.Error()
		err = fmt.Errorf("期数获取失败")
		return
	}
	for _, policyReport := range policyReports {
		contentSub := ""
		maxStage += 1
		if policyReport.Content != "" {
			contentSub, err = GetReportContentSub(policyReport.Content)
			if err != nil {
				errMsg = "策略报告 批量同步 ContentSub 失败，Err:" + err.Error()
				err = fmt.Errorf("截取内容失败")
				return
			}
		}

		item := new(models.EnglishReport)
		item.AddType = 1
		item.ClassifyIdFirst = classifyInfo.ParentId
		item.ClassifyNameFirst = classifyInfo.ParentClassifyName
		item.ClassifyIdSecond = classifyInfo.Id
		item.ClassifyNameSecond = classifyInfo.ClassifyName
		item.Title = "China A-share Daily Check-in"
		item.Abstract = "China A-share market and economic data review"
		item.Author = "Horizon Insights FICC Team"
		item.Frequency = policyReport.Frequency
		item.State = 1
		item.Content = policyReport.Content
		item.Stage = maxStage
		item.ContentSub = html.EscapeString(contentSub)
		item.CreateTime = time.Now().Format(utils.FormatDateTime)
		item.ModifyTime = time.Now()
		item.Overview = policyReport.Abstract
		item.KeyTakeaways = policyReport.KeyTakeaways
		item.FromReportId = policyReport.Id
		newReportId, e := models.AddEnglishReport(item)
		if e != nil {
			errMsg = "保存研报失败,Err:" + e.Error()
			err = fmt.Errorf("保存研报失败")
			return
		}
		reportCode := utils.MD5(strconv.Itoa(int(newReportId)))
		//修改唯一编码
		err = models.ModifyEnglishReportCode(newReportId, reportCode)
		if err != nil {
			errMsg = "更新英文研报失败,Err:" + err.Error()
			err = fmt.Errorf("更新英文研报失败")
			return
		}
		//更新策略报告状态为已同步
		if err = models.SyncEnglishPolicyReportById(policyReport.Id, int(newReportId)); err != nil {
			errMsg = "更新策略报告失败,Err:" + err.Error()
			err = fmt.Errorf("更新策略报告失败")
			return
		}
	}
	return
}

// 取消英文策略报告一键同步
func EnglishPolicyReportSyncCancel(reportInfo *models.EnglishReportDetail) (err error) {
	var policyReport *models.EnglishPolicyReportDetail
	if reportInfo.FromReportId > 0 {
		//查询报告是否存在
		policyReport, err = models.GetEnglishPolicyReportById(reportInfo.FromReportId)
		if err != nil {
			if err.Error() == utils.ErrNoRow() {
				err = fmt.Errorf("报告不存在！")
				return
			}
			err = fmt.Errorf("获取报告信息失败,Err:%v", err)
			return
		}
		//判断报告是否已同步
		if policyReport.State == 1 {
			err = fmt.Errorf("报告已取消同步，无需重复取消")
			return
		}

		if err = models.SyncCancelEnglishPolicyReport(policyReport.Id); err != nil {
			err = fmt.Errorf("报告已取消同步失败 Err %v", err)
			return
		}
	}
	return
}

// UpdateEnglishCompanyEnabledByCompanyId 根据英文客户ID更新状态
func UpdateEnglishCompanyEnabledByCompanyId(companyId int) (err error) {
	defer func() {
		if err != nil {
			alarm_msg.SendAlarmMsg(fmt.Sprintf("更新英文客户状态失败, Err: %s", err.Error()), 3)
		}
	}()

	// 获取客户
	comp, e := models.GetEnglishCompanyById(companyId)
	if e != nil {
		err = fmt.Errorf("英文客户已被删除")
		return
	}

	// 获取联系人
	emailCond := ` AND company_id = ?`
	emailPars := make([]interface{}, 0)
	emailPars = append(emailPars, companyId)
	emailList, e := models.GetEnglishReportEmailList(emailCond, emailPars, "")
	if e != nil {
		err = fmt.Errorf("获取英文联系人列表失败, Err: %s", e.Error())
		return
	}
	// 无联系人, 保持原状态
	total := len(emailList)
	if total == 0 {
		return
	}

	// 判断状态, 是否部分禁用
	status := 0
	enabledCount := 0
	for _, v := range emailList {
		if v.Enabled == 1 {
			enabledCount += 1
		}
	}
	if enabledCount == 0 {
		status = models.EnglishCompanyDisabled
	}
	if total == enabledCount {
		status = models.EnglishCompanyEnabled
	}
	if total > enabledCount && enabledCount != 0 {
		status = models.EnglishCompanyHalfEnabled
	}

	// 是否需要更新
	if comp.Enabled == status {
		return
	}
	comp.Enabled = status
	comp.ModifyTime = time.Now().Local()
	if e = comp.Update([]string{"Enabled", "ModifyTime"}); e != nil {
		err = fmt.Errorf("更新客户状态失败, Err: %s", e.Error())
		return
	}
	return
}
