package wechat

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"eta/eta_mini_api/models"
	"eta/eta_mini_api/utils"
	"fmt"
	"io"
	"net/http"
	"time"
)

var (
	TemplateMsgSendUrl       = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s"
	TemplateMsgClearQuotaUrl = "https://api.weixin.qq.com/cgi-bin/clear_quota?access_token=%s"
)

type TemplateMsgSendClient struct {
	AccessToken string
	Data        []byte
}

type SendTemplateResponse struct {
	Errcode int    `json:"errcode"`
	Errmsg  string `json:"errmsg"`
	MsgID   int    `json:"msgid"`
}

type ClearQuotaResponse struct {
	Errcode int    `json:"errcode"`
	Errmsg  string `json:"errmsg"`
}

type OpenIdList struct {
	OpenId string
	UserId int
}

// TemplateMsgSendClient.ClearQuota 清除发送超过当日10万次限制
func (c *TemplateMsgSendClient) ClearQuota() (result *ClearQuotaResponse, err error) {
	key := "CACHE_SendTemplateMsg_ERR"
	exists, _ := utils.Redis.Exists(context.TODO(), key).Result()
	if exists == 1 {
		return
	}
	_ = utils.Redis.SetEX(context.TODO(), key, 1, 6*time.Minute)

	sendUrl := fmt.Sprintf(TemplateMsgClearQuotaUrl, c.AccessToken)
	client := http.Client{}
	clearData := make(map[string]interface{})
	clearData["appid"] = WxAppId
	clearJson, _ := json.Marshal(clearData)
	resp, err := client.Post(sendUrl, "application/json", bytes.NewBuffer(clearJson))
	if err != nil {
		return
	}
	defer func() {
		_ = resp.Body.Close()
	}()
	clearBody, err := io.ReadAll(resp.Body)
	err = json.Unmarshal(clearBody, &result)
	return
}

// TemplateMsgSendClient.SendMsg 推送消息
func (c *TemplateMsgSendClient) SendMsg() (sendRes *SendTemplateResponse, err error) {
	// 请求接口
	sendUrl := fmt.Sprintf(TemplateMsgSendUrl, c.AccessToken)
	client := http.Client{}
	resp, err := client.Post(sendUrl, "application/json", bytes.NewBuffer(c.Data))
	if err != nil {
		return
	}
	defer func() {
		_ = resp.Body.Close()
	}()
	body, _ := io.ReadAll(resp.Body)
	if err = json.Unmarshal(body, &sendRes); err != nil {
		return
	}
	// 模板消息发送超过当日10万次限制错误处理
	if sendRes.Errcode == 45009 {
		// 发送提示邮件
		// 清理限制
		clearRes, e := c.ClearQuota()
		if e != nil {
			err = e
			return
		}
		if clearRes.Errcode != 0 {
			clearJson, er := json.Marshal(clearRes)
			if er != nil {
				return nil, er
			}
			fmt.Println("自动清理模板消息限制接口, 调用失败, ClearQuotaResponse: " + string(clearJson))
			return
		}
		// 发送成功邮件
		// 重新推送
		go func() {
			_, e := c.SendMsg()
			if e != nil {
				return
			}
		}()
	}
	if sendRes.Errcode != 0 {
		err = errors.New("推送模板消息失败, SendTemplateResponse: " + string(body))
	}
	return
}

// AddUserTemplateRecord 新增模板消息推送记录
func AddUserTemplateRecord(userId, sendStatus, sendType int, openid, resource, sendData, result string) (err error) {
	item := &models.UserTemplateRecord{
		UserID:     userId,
		OpenID:     openid,
		Resource:   resource,
		SendData:   sendData,
		Result:     result,
		CreateDate: time.Now().Format(utils.FormatDate),
		CreateTime: time.Now().Format(utils.FormatDateTime),
		SendStatus: sendStatus,
		SendType:   sendType,
	}
	err = item.Insert()
	return
}

// SendMultiTemplateMsg 推送模板消息至多个用户
func SendMultiTemplateMsg(sendMap map[string]interface{}, items []*OpenIdList, resource string, sendType int) (err error) {
	ws := GetWxChat()
	accessToken, err := ws.GetAccessToken()
	if err != nil {
		return
	}
	for _, item := range items {
		sendMap["touser"] = item.OpenId
		data, e := json.Marshal(sendMap)
		if e != nil {
			err = e
			return
		}
		ts := &TemplateMsgSendClient{
			AccessToken: accessToken,
			Data:        data,
		}
		result, e := ts.SendMsg()
		if result == nil {
			return
		}
		// 推送消息记录
		{
			go func(v *OpenIdList) {
				sendStatus := 1
				if e != nil {
					sendStatus = 0
				}
				resultJson, _ := json.Marshal(result)
				_ = AddUserTemplateRecord(v.UserId, sendStatus, sendType, v.OpenId, resource, string(data), string(resultJson))
			}(item)
		}
		if e != nil {
			err = e
			return
		}
	}
	return
}