package tasks

import (
	"encoding/xml"
	"gitee.ltd/lxh/wechat-robot/internal/minio"
	"gitee.ltd/lxh/wechat-robot/internal/model"
	"gitee.ltd/lxh/wechat-robot/internal/types"
	"gitee.ltd/lxh/wechat-robot/internal/wechat"
	"gitee.ltd/lxh/xybot"
	"github.com/gofiber/fiber/v2/log"
	"strings"
	"time"
)

// syncMessage
// @description: 同步指定机器人的消息
// @param containerHost 机器人接口地址
// @param robotWxId 机器人微信Id
// @param robotId 机器人数据Id
func syncMessage(client *xybot.Client, robotId uint) {
	// 获取数据库连接
	db := model.GetDB()

	// 获取新消息
	messages, err := client.Message.Sync()
	if err != nil {
		// 手动处理一下是否离线了
		isOffline := strings.Contains(err.Error(), "用户可能退出") || strings.Contains(err.Error(), "数据[DecryptData]失败")
		if isOffline {
			// 删除定时任务
			DeleteJob(robotId)
			// 修改机器人状态
			db.Model(&model.Robot{}).Where("id = ?", robotId).Update("status", "offline")
		}

		return
	}

	if len(messages) == 0 {
		// 没有消息，直接返回
		return
	}
	//log.Debugf("当前同步机器人Id: %d，消息数量: %d，客户端信息: %+v", robotId, len(messages), client)

	// 处理消息
	var msg []model.Message
	for _, message := range messages {
		//log.Debugf("当前同步机器人Id: %d，消息内容: %s", robotId, message.Content.String)
		var m model.Message
		m.RobotId = robotId
		m.MsgId = message.NewMsgId
		m.ClientMsgId = message.MsgId
		m.CreateTime = message.CreateTime
		m.CreateAt = time.Unix(int64(message.CreateTime), 0)
		m.Type = types.MessageType(message.MsgType)
		m.Content = message.Content.String
		m.DisplayFullContent = message.PushContent
		m.FromUser = message.FromUserName.String
		m.ToUser = message.ToWxid.String

		// 如果是群聊消息，单独处理一下
		// Sys类型的消息正文不包含微信 Id，所以不需要处理
		if strings.HasSuffix(message.FromUserName.String, "@chatroom") && m.Type != types.MsgTypeSys {
			// 群消息，处理一下消息和发信人
			groupUser := strings.Split(m.Content, "\n")[0]
			groupUser = strings.ReplaceAll(groupUser, ":", "")
			// 如果两个id一致，说明是系统发的
			if m.FromUser != groupUser {
				m.GroupUser = groupUser
			}
			// 用户的操作单独提出来处理一下
			m.Content = strings.Join(strings.Split(m.Content, "\n")[1:], "\n")
		}

		// 处理一下，如果是图片、文件、表情包等信息，直接下载下来存到OSS
		if m.Type == types.MsgTypeImage || m.Type == types.MsgTypeVideo {
			// 解析消息xml文件
			// 解析为结构体
			var media wechat.MediaMessage
			if err = xml.Unmarshal([]byte(m.Content), &media); err != nil {
				log.Errorf("%v解析消息失败: %v", m.Type, err.Error())
				continue
			}

			var md5Str, bs64Str string
			switch m.Type {
			case types.MsgTypeImage:
				fileUrl := ""
				md5Str = media.Img.Md5
				if media.Img.CdnBigImgUrl != "" {
					fileUrl = media.Img.CdnBigImgUrl
				} else if media.Img.CdnMidImgUrl != "" {
					fileUrl = media.Img.CdnMidImgUrl
				} else if media.Img.CdnThumbUrl != "" {
					fileUrl = media.Img.CdnThumbUrl
				} else {
					continue
				}
				if bs64Str, err = client.Tool.CdnDownloadImg(media.Img.AesKey, fileUrl); err != nil {
					log.Errorf("图片文件下载失败: %s", err.Error())
					continue
				}
			case types.MsgTypeVideo:
				if bs64Str, err = client.Tool.DownloadVideo(m.ClientMsgId); err != nil {
					log.Errorf("视频文件下载失败: %s", err.Error())
					continue
				}
			}

			// 下载完成，保存到OSS
			if m.FileUrl, err = minio.SaveBase64(bs64Str, md5Str); err != nil {
				log.Errorf("文件保存到Minio失败: %s", err.Error())
				continue
			}
		}

		msg = append(msg, m)
	}
	// 保存入库
	db.Save(&msg)
}
