package services

import (
	"encoding/json"
	"errors"
	"fmt"
	"hongze/hz_crm_api/models"
	"hongze/hz_crm_api/services/alarm_msg"
	"hongze/hz_crm_api/utils"
	"html"
	"strconv"
	"strings"
	"time"
)

// 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:"模板内容主体"`
}

// 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 {
			go alarm_msg.SendAlarmMsg("阿里云群发英文研报邮件失败, Err: "+err.Error(), 3)
		}
	}()
	if len(list) == 0 {
		return
	}
	requestMap := make(map[int]*EnglishReportSendEmailRequest, 0)
	for i := range list {
		requestMap[list[i].EmailId] = list[i]
	}

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

	// 返回的结果更新日志
	resendList := make([]*EnglishReportSendEmailRequest, 0)
	failLogIds := make([]int, 0)
	updateCols := []string{"SendData", "Result", "SendStatus", "ErrMsg"}
	for i := range resultList {
		var cond string
		var pars []interface{}
		cond = ` AND is_deleted = 0 AND report_id = ? AND email_id = ? AND source = ? AND send_status = ?`
		pars = append(pars, resultList[i].ReportId, resultList[i].EmailId, models.EnglishReportEmailLogSourceAli, models.EnglishReportEmailLogStatusIng)
		l, e := models.GetEnglishReportEmailLog(cond, pars)
		if e != nil {
			continue
		}
		l.SendData = resultList[i].SendData
		l.Result = resultList[i].ResultData
		if resultList[i].Ok {
			l.SendStatus = models.EnglishReportEmailLogStatusSuccess
		} else {
			l.SendStatus = models.EnglishReportEmailLogStatusFail
			failLogIds = append(failLogIds, l.Id)
			if requestMap[resultList[i].EmailId] != nil {
				resendList = append(resendList, requestMap[resultList[i].EmailId])
			}
			// 取出错误信息
			r := new(AliyunEmailResult)
			if e = json.Unmarshal([]byte(resultList[i].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
		}
		if e = l.Update(updateCols); e != nil {
			continue
		}
	}

	// 推送失败的重新腾讯云, 若腾讯云也失败将不再自动重推, 用户手动去重推
	if len(resendList) > 0 && len(failLogIds) > 0 {
		_ = ResendTencentEnglishReportEmail(resendList, failLogIds)
	}
	return
}

// ResendTencentEnglishReportEmail 腾讯云邮件重新推送
func ResendTencentEnglishReportEmail(resendList []*EnglishReportSendEmailRequest, failLogIds []int) (err error) {
	defer func() {
		if err != nil {
			go alarm_msg.SendAlarmMsg("腾讯云重发英文研报邮件失败, Err: "+err.Error(), 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)
	for i := range resendList {
		sendByte, e := json.Marshal(resendList[i])
		if e != nil {
			err = errors.New("sendByte json.Marshal Err, Err: " + e.Error())
			return
		}

		logData = append(logData, &models.EnglishReportEmailLog{
			ReportId:   resendList[i].ReportId,
			EmailId:    resendList[i].EmailId,
			Email:      resendList[i].Email,
			SendData:   string(sendByte),
			Source:     models.EnglishReportEmailLogSourceTencent,
			SendStatus: models.EnglishReportEmailLogStatusIng,
			CreateTime: nowTime,
		})
	}
	emailLog := new(models.EnglishReportEmailLog)
	if e := emailLog.InsertMulti(logData); e != nil {
		err = errors.New("批量写入群发邮件日志失败, Err: " + e.Error())
		return
	}

	// 请求腾讯云
	tecentEmail := new(TencentEmail)
	resultList, e := tecentEmail.BatchSendEmail(resendList)
	if e != nil {
		err = e
		return
	}
	updateCols := []string{"SendData", "Result", "SendStatus", "ErrMsg"}
	for i := range resultList {
		var cond string
		var pars []interface{}
		cond = ` AND is_deleted = 0 AND report_id = ? AND email_id = ? AND source = ? AND send_status = ?`
		pars = append(pars, resultList[i].ReportId, resultList[i].EmailId, models.EnglishReportEmailLogSourceTencent, models.EnglishReportEmailLogStatusIng)
		l, e := models.GetEnglishReportEmailLog(cond, pars)
		if e != nil {
			continue
		}
		l.SendData = resultList[i].SendData
		l.Result = resultList[i].ResultData
		if resultList[i].Ok {
			l.SendStatus = models.EnglishReportEmailLogStatusSuccess
		} else {
			l.SendStatus = models.EnglishReportEmailLogStatusFail
			r := new(TencentEmailResult)
			if e = json.Unmarshal([]byte(resultList[i].ResultData), &r); e != nil {
				continue
			}
			l.ErrMsg = r.Message
		}
		if e = l.Update(updateCols); e != nil {
			continue
		}
	}
	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
}

// 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
}
