// package asChat -----------------------------
// @file      : handler.go
// @author    : JJXu
// @contact   : wavingbear@163.com
// @time      : 2022/10/23 11:13:43
// -------------------------------------------
package asChat

import (
	"bytes"
	"context"
	"crypto/md5"
	"encoding/hex"
	"errors"
	"fmt"
	"fonchain-fiee/api/accountFiee"
	"fonchain-fiee/cmd/config"
	"fonchain-fiee/pkg/common/jwt"
	"fonchain-fiee/pkg/common/ws"
	"fonchain-fiee/pkg/e"
	"fonchain-fiee/pkg/service"
	"fonchain-fiee/pkg/service/asChat/chatCache"
	"fonchain-fiee/pkg/service/asChat/consts"
	"fonchain-fiee/pkg/service/asChat/dto"
	"fonchain-fiee/pkg/service/asChat/logic"
	"fonchain-fiee/pkg/service/asChat/robot"
	"fonchain-fiee/pkg/service/upload"
	"fonchain-fiee/pkg/utils"
	"fonchain-fiee/pkg/utils/stime"
	"io"
	"log"
	"path"
	"slices"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/fonchain/utils/voice"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	uuid "github.com/satori/go.uuid"
	"go.uber.org/zap"
)

var ChatHandlerIns = ChatHandler{
	cache: chatCache.ChatCache{NewMessageStatExpireAfter: 10 * time.Minute},
	robot: robot.NewRobot(),
}

type ChatHandler struct {
	cache chatCache.ChatCache
	robot *robot.Robot
}

func (cr ChatHandler) Connection(c *gin.Context) {
	conn, err := ws.UpGrader.Upgrade(c.Writer, c.Request, nil)
	conn.SetReadDeadline(time.Now().Add(time.Second * 10))
	if err != nil {
		log.Print("无法升级为websocket连接", zap.Error(err))
		c.String(500, "无法转为websocket连接")
		return
	}
	defer func() {
		if conn != nil {
			conn.Close()
		}
	}()
	_, byteData, err := conn.ReadMessage()
	if err != nil {
		_ = conn.WriteMessage(websocket.TextMessage, ws.WsErrorConnection("null", err.Error(), "conn.ReadMessag1"))
		return
	}
	fmt.Println("22222222222222,AuthorizationVerify")
	var ok bool
	var userInfo *accountFiee.ChatUserData
	userInfo, ok, err = ws.AuthorizationVerify(byteData)
	if err != nil {
		_ = conn.WriteMessage(websocket.TextMessage, ws.WsErrorConnection("null", err.Error(), "AuthorizationVerify2"))
		return
	}
	if !ok {
		_ = conn.WriteMessage(websocket.TextMessage, ws.WsErrorConnection("null", "登录状态失效", "AuthorizationVerify2.1"))
		return
	}
	fmt.Println("33333333333333,RecountNewMessageTotal")
	conn.SetReadDeadline(time.Time{})
	go cr.cache.RecountNewMessageTotal(userInfo.ID)

	fmt.Println("44444444444444,ws.NewClient")
	//注册ws客户端,并发送clientId给ws客户端
	var cli = ws.NewClient(userInfo.ID, "", conn, consts.ChatRoom)
	cli.Waiter = userInfo.Role == 2
	fmt.Println("55555555555555,GetUserSession")
	//查询是否有历史的sessionId
	cli.SessionId = cr.cache.GetUserSession(userInfo.ID)
	consts.ChatRoom.Register(cli)
	cr.cache.SaveUserSession(userInfo.ID, cli.SessionId)
	fmt.Println("66666666666666666666666666")
	go cli.WriteWait()
	cli.Send <- consts.WsMessageRegisterCallback(cli.ClientId, cli.SessionId)
	fmt.Println("777777777777777777777777")
	// 处理websocket连接的逻辑
	ctx, _ := context.WithCancel(context.Background())
	cli.Reading(ctx, HandleMessage)
	fmt.Println("88888888888888888888888888")
	select {
	case <-ctx.Done():
		return
	}
}

func (cr ChatHandler) NewMessage(c *gin.Context) {
	var request dto.NewMessageRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		service.Error(c, err)
		return
	}
	if request.SessionId == "" {
		service.Error(c, errors.New("sessionId不能为空"))
		return
	}
	if request.MsgType == 0 {
		service.Error(c, errors.New("msgType不能为空"))
		return
	}
	fmt.Println("NewMessage 1111111111111111111111111111111")
	//获取用户信息
	chatUser, code := jwt.ParseToChatUser(c)
	if code != 0 {
		service.ErrWithCode(c, code)
		return
	}
	err := logic.NewMessage(c, &cr.cache, chatUser, request)
	if err != nil {
		service.Error(c, err)
		return
	}

	//fmt.Println("NewMessage 22222222222222222222222222222222222")
	////存储入库
	//if chatUser.NickName != "" {
	//	chatUser.NickName = fmt.Sprintf("未知用户(%d)", chatUser.ID)
	//}
	//fmt.Println("NewMessage 3333333333333333333333333333333333")
	//var data = accountFiee.ChatRecordData{
	//	SessionId:  request.SessionId,
	//	UserId:     chatUser.ID,
	//	Name:       chatUser.NickName,
	//	Avatar:     "",
	//	MsgType:    request.MsgType,
	//	Content:    request.Message.Text,
	//	LocalStamp: request.LocalStamp,
	//	Medias:     nil,
	//}
	//if len(request.Message.Media) > 0 {
	//	for _, media := range request.Message.Media {
	//		data.Medias = append(data.Medias, &accountFiee.ChatMediaData{
	//			ID: media.MediaId,
	//		})
	//	}
	//}
	//fmt.Println("NewMessage 4444444444444444444444444444444444")
	//resp, err := service.AccountFieeProvider.CreateChatRecord(c, &data)
	//if err != nil {
	//	service.Error(c, errors.New("创建失败"))
	//	return
	//}
	//fmt.Printf("CreateChatRecord resp:%+v\n", resp)
	////录入缓存
	//err = cr.cache.AddChatRecord(request.SessionId, resp.Data)
	//if err != nil {
	//	service.Error(c, errors.New("创建失败"))
	//	return
	//}
	//fmt.Println("NewMessage 5 消息数量+1")
	////新消息数量统计+1
	//noticeUserId := consts.ChatRoom.GetUserIdInSession(request.SessionId, chatUser.ID)
	//fmt.Println("NewMessage 5.1 消息数量配置结束")
	//fmt.Printf("noticeUserId %+v\n", noticeUserId)
	//for _, userId := range noticeUserId {
	//	fmt.Println("userId")
	//	cr.cache.IncreaseNewMessageTotal(userId, request.SessionId)
	//}
	//fmt.Println("NewMessage 6")
	////发送websocket消息提醒通知
	//var notice = dto.MessageListType{}
	//notice.BuildMessage(resp.Data)
	//fmt.Printf("ws消息提醒:%+v\n", notice)
	//_, err = consts.ChatRoom.SendSessionMessage(chatUser.ID, request.SessionId, ws.NewChatMsgType, notice)
	//if err != nil {
	//	log.Print("发送新消息通知失败", zap.Error(err), zap.Any("notice", notice))
	//}
	//cr.robot.Listen(&data)
	//fmt.Println("NewMessage 7 -end")
	////发送app推送(无横幅推送)
	////go func() {
	////	omitMessage := ""
	////	switch request.MsgType {
	////	case accountFiee.MsgType_TextMsgType:
	////		runMsg := []rune(request.Text)
	////		if len(runMsg) > 15 {
	////			omitMessage = string(runMsg[:15]) + "..."
	////		} else {
	////			omitMessage = request.Text
	////		}
	////	case accountFiee.MsgType_ImageMsgType:
	////		omitMessage = "[图片]"
	////	case accountFiee.MsgType_AudioMsgType:
	////		omitMessage = "[音频]"
	////	case accountFiee.MsgType_VideoMsgType:
	////		omitMessage = "[视频]"
	////	default:
	////		omitMessage = "新消息请查收"
	////	}
	////	for _, userId := range noticeUserId {
	////		_ = asPusher.NewArtistinfoUniPush().NewChatMessageNotice(userId, omitMessage)
	////	}
	////}()
	service.Success(c)
}

func (cr ChatHandler) MessageList(c *gin.Context) {
	var request dto.MessageListRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		service.Error(c, err)
		return
	}
	domain := c.GetHeader("domain")
	fmt.Println("MessageList domain:", domain)
	if (request.Direction == 0 && !request.Recent) || (request.Direction > 0 && request.Recent) {
		service.Error(c, errors.New("组合条件校验失败"))
		return
	}
	if request.SessionId == "" {
		service.Error(c, errors.New("sessionId不能为空"))
		return
	}
	if request.PageSize < -1 {
		service.Error(c, errors.New("pageSize校验错误"))
		return
	}
	var resp = make([]*dto.MessageListType, 0)
	if request.CurrentId == 0 && request.Direction == 1 {
		service.Success(c, resp)
		return
	}
	chatUser, code := jwt.ParseToChatUser(c)
	if code != 0 {
		service.ErrWithCode(c, code)
		return
	}
	//if request.SessionId == "" {
	//	request.SessionId = cr.cache.GetUserSession(tokenResult.UserInfo.ID)
	//	if request.SessionId == "" {
	//		service.Success(c, resp)
	//		return
	//	}
	//}
	//messages := cr.cache.GetChatRecord(request.SessionId)
	messages := []*accountFiee.ChatRecordData{}
	var returnDataIdList = make([]int64, 0)
	defer func() {
		//获取最新数据时,重置新消息数量统计
		if request.Direction == 2 || request.Recent {
			cr.cache.ResetNewMessageTotal(chatUser.ID, request.SessionId)
		}
		//设置消息已被客服阅读,当客服重新通过通过websocket连接时,这些消息将不被纳入新消息数量统计
		if len(returnDataIdList) > 0 && domain == "fontree" {
			for _, hasReadId := range returnDataIdList {
				for i, message := range messages {
					if message.ID == hasReadId {
						messages[i].WaiterRead = 1
					}
				}
			}
			err := cr.cache.CoverChatRecord(request.SessionId, messages)
			if err != nil {
				log.Print("设置消息已读失败", zap.Error(err))
			}
			for _, v := range messages {
				_, err = service.AccountFieeProvider.SaveChatRecord(context.Background(), v)
				if err != nil {
					log.Print("设置消息已读失败", zap.Error(err))
				}
			}
		}
	}()
	if len(messages) == 0 {
		//从数据库获取
		recordResp, err := service.AccountFieeProvider.GetChatRecordList(c, &accountFiee.GetChatRecordListRequest{
			Query:    &accountFiee.ChatRecordData{SessionId: request.SessionId},
			Page:     1,
			PageSize: -1,
			//Where:    fmt.Sprintf("id %s %d", utils.IfGec(request.Direction == 1, "<", ">"), request.CurrentId),
		})
		if err != nil {
			service.Error(c, err)
			return
		}
		messages = recordResp.List
		err = cr.cache.CoverChatRecord(request.SessionId, messages)
		if err != nil {
			log.Print("覆盖聊天记录失败", zap.Error(err))
		}
	}
	if request.Recent {
		if int64(len(messages)) >= request.PageSize {
			messages = messages[len(messages)-int(request.PageSize):]
		}
		var now = time.Now()
		for _, message := range messages {
			if request.InHour > 0 {
				messageCreatedAt, _ := stime.StringToTime(message.CreatedAt)
				if now.Sub(*messageCreatedAt) >= request.InHour*time.Hour {
					continue
				}
			}
			returnDataIdList = append(returnDataIdList, message.ID)
			var msg = &dto.MessageListType{}
			msg.BuildMessage(message)
			resp = append(resp, msg)
		}
	} else {
		sort.Slice(messages, func(i, j int) bool {
			if request.Direction == 1 {
				return messages[i].ID < messages[j].ID
			} else {
				return messages[i].ID > messages[j].ID
			}
		})
		fmt.Printf("data is %+v\n", messages)
		total := 0
		for i, message := range messages {
			switch request.Direction {
			case 1: //向下查找,找比CurrentId大的数据
				if message.ID <= request.CurrentId {
					continue
				}
			case 2: //向上查找,找比CurrentId小的数据
				if message.ID >= request.CurrentId {
					continue
				}
			}
			message := message
			fmt.Println(i, message.ID)
			if request.PageSize != -1 && int64(total+1) > request.PageSize {
				continue
			}
			total++
			returnDataIdList = append(returnDataIdList, message.ID)
			var msg = &dto.MessageListType{}
			msg.BuildMessage(message)
			resp = append(resp, msg)
		}
	}
	//二次排序
	sort.Slice(resp, func(i, j int) bool {
		return resp[i].ID < resp[j].ID
	})
	//优化空列表
	for i, v := range resp {
		if v.Message.Media == nil {
			resp[i].Message.Media = []dto.MessageMedia{}
		}
	}
	service.Success(c, resp)
}

func (cr ChatHandler) Upload(c *gin.Context) {
	fmt.Println("111111111111")
	//获取用户信息
	chatUser, code := jwt.ParseToChatUser(c)
	if code != 0 {
		service.ErrWithCode(c, code)
		return
	}
	fmt.Printf("chatUser is %#v\n", chatUser)
	//获取文件对象
	file, err := c.FormFile("file")
	if err != nil {
		log.Print("ERROR: upload file failed. ", zap.Error(err))
		return
	}
	duration := c.PostForm("duration")
	fmt.Println(duration)
	ext := c.PostForm("ext")
	fileExt := strings.ToLower(path.Ext(file.Filename))
	if ext != "" {
		fileExt = ext
	}
	fileType := e.DetectFileTypeByExtension(fileExt)
	if fileType == e.Audio {
		if !slices.Contains([]string{".mp4", ".aac", ".mp3", ".opus", ".wav"}, fileExt) {
			service.Error(c, errors.New("不支持的格式"))
			return
		}
	}
	//计算md5
	tmp, err := file.Open()
	if err != nil {
		service.Error(c, errors.New("上传失败"))
		return
	}
	fileContent, err := io.ReadAll(tmp)
	if err != nil {
		service.Error(c, errors.New("文件读取失败"))
		return
	}
	hash := md5.New()
	_, err = hash.Write(fileContent)
	if err != nil {
		service.Error(c, errors.New("文件读取失败"))
		return
	}
	md5Bytes := hash.Sum(nil)                 // 获取 MD5 字节切片
	md5String := hex.EncodeToString(md5Bytes) // 转换为十六进制字符串表示
	//检查文件是否存在
	checkResp, err := service.AccountFieeProvider.GetChatMediaList(c, &accountFiee.GetChatMediaListRequest{Query: &accountFiee.ChatMediaData{Md5: md5String}, Page: 1, PageSize: 1})
	if err != nil {
		log.Print("md5查询附件失败", zap.Error(err))
	}
	if checkResp != nil && checkResp.Total > 0 {
		service.Success(c, checkResp.List[0])
		return
	}

	//文件不存在则上传文件
	filename, _ := uuid.NewV4()
	defer tmp.Close()
	fileBuffer := bytes.NewBuffer(fileContent)
	var bosUrl string
	bosUrl, err = upload.UploadWithBuffer(fileBuffer, fmt.Sprintf("fiee/%d/%v%v", chatUser.ID, filename, fileExt))
	if err != nil {
		service.Error(c, err)
		return
	}
	//存到数据库
	var durationInt64, _ = strconv.ParseInt(duration, 10, 64)
	var mediaData = accountFiee.ChatMediaData{
		Url:      bosUrl,
		Md5:      md5String,
		Size:     fmt.Sprintf("%d", file.Size),
		Ext:      fileExt,
		Duration: durationInt64,
	}
	resp, err := service.AccountFieeProvider.CreateChatMedia(c, &mediaData)
	if err != nil {
		service.Error(c, err)
		return
	}
	service.Success(c, resp.Data)
}

func (cr ChatHandler) UserMessageStat(c *gin.Context) {
	var request accountFiee.GetChatUserListRequest2
	if err := c.ShouldBindJSON(&request); err != nil {
		service.Error(c, err)
		return
	}
	//获取用户信息
	chatUser, code := jwt.ParseToChatUser(c)
	if code != 0 {
		service.ErrWithCode(c, code)
		return
	}
	result := cr.cache.GetNewMessageStat(c, chatUser.ID)
	if len(result) == 0 {
		service.Success(c, result)
		return
	}
	fmt.Printf("cache stat:%+v\n", result)
	request.Page = 1
	request.PageSize = int64(len(result))
	for i, item := range result {
		if item.UserId == 0 {
			sessionId, _ := strconv.Atoi(item.SessionId)
			item.UserId = int64(sessionId)
			result[i].UserId = int64(sessionId)
		}
		request.UserIdIn = append(request.UserIdIn, item.UserId)
	}
	fmt.Printf("protoReq.UserIdIn:%+v\n", request.UserIdIn)
	listRes, err := service.AccountFieeProvider.GetChatUserList2(c, &request)
	if err != nil {
		service.Error(c, err)
		return
	}
	fmt.Printf("GetChatUserList:%+v\n", listRes)
	for i, item := range result {
		for _, user := range listRes.List {
			if item.UserId == user.UserId {
				user := user
				result[i].Name = user.Name
				//result[i].ArtistUid = user.ArtistUid
				break
			}
		}
		if result[i].Name == "" {
			result[i].Name = beautifulZeroName(result[i].Name, result[i].UserId)
		}
	}
	reverse(result)
	service.Success(c, result)
}
func reverse(slice []dto.UserMsgStatic) {
	for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 {
		slice[i], slice[j] = slice[j], slice[i]
	}
}
func (cr ChatHandler) VoiceToText(c *gin.Context) {
	var req dto.VoiceToTextRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		service.Error(c, err)
		return
	}
	detail, err := service.AccountFieeProvider.GetChatMediaDetail(c, &accountFiee.GetChatMediaByIdRequest{Id: req.MediaId})
	if err != nil {
		service.Error(c, err)
		return
	}
	if detail.ConvText != "" {
		service.Success(c, map[string]string{"convText": detail.ConvText})
		return
	}
	voiceApi := voice.NewVoiceApi()
	detail.ConvText, err = voiceApi.ToTextFromUrl(detail.Url)
	if err != nil {
		service.Error(c, errors.New("语音转文字失败"))
		return
	}
	defer func() {
		service.AccountFieeProvider.UpdateChatMedia(context.Background(), detail)
	}()
	service.Success(c, map[string]string{"convText": detail.ConvText})
}

func (cr ChatHandler) UserDetail(c *gin.Context) {
	var req dto.UserDetailReq
	if err := c.ShouldBindJSON(&req); err != nil {
		service.Error(c, err)
		return
	}
	if req.UserId == 0 {
		service.Success(c, dto.ArtistInfo{})
		return
	}
	resp, err := service.AccountFieeProvider.Info(c, &accountFiee.InfoRequest{ID: req.UserId, Domain: config.AppConfig.System.Domain})
	if err != nil {
		service.Error(c, err)
		return
	}
	service.Success(c, resp)
}

// 对没有名字的name进行优化
func beautifulZeroName(name string, userId int64) string {
	return utils.IfGec(name == "", fmt.Sprintf("未实名用户:%d", userId), name)
}