package service

import (
	"errors"
	"fmt"
	"gadmin/config"
	"gadmin/internal/admin/consts"
	"gadmin/internal/admin/forms"
	"gadmin/internal/gorm/model"
	"gadmin/internal/gorm/query"
	"gadmin/utility/player"
	"gadmin/utility/serializer"
	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
	"io"
	"net/http"
	"strings"
	"time"
)

var ChatReport = new(chatReportService)

type chatReportService struct{}

func (s *chatReportService) List(ctx *gin.Context, req *forms.ChatReportListReq) serializer.Response {
	var (
		q            = query.Use(config.DB).ChatReportLog
		m            = q.WithContext(ctx)
		offset int64 = 0
		list   []model.ChatReportLog
	)
	if req.PlayerID > 0 {
		m = m.Where(q.PlayerID.Eq(req.PlayerID))
	}
	if req.ClanPlayerID > 0 {
		m = m.Where(q.ClanPlayerID.Eq(req.ClanPlayerID))
	}
	if req.ServerID != 0 {
		m = m.Where(q.ServerID.Eq(req.ServerID))
	}
	if req.ClanServerID != 0 {
		m = m.Where(q.ClanServerID.Eq(req.ClanServerID))
	}
	if req.ClanChatChannel != 0 {
		m = m.Where(q.ClanChatChannel.Eq(req.ClanChatChannel))
	}
	if len(req.CreateTime) == 2 {
		m = m.Where(q.CreateTime.Between(req.CreateTime[0], req.CreateTime[1]))
	}
	if len(req.ClanTime) == 2 {
		m = m.Where(q.ClanTime.Between(req.ClanTime[0], req.ClanTime[1]))
	}

	if len(req.Sorter) > 0 {
		for i := 0; i < len(req.Sorter); i++ {
			if req.Sorter[i].Field == "id" {
				if req.Sorter[i].By == "DESC" {
					m = m.Order(q.ID.Desc())
				} else {
					m = m.Order(q.ID)
				}
			}
			if req.Sorter[i].Field == "clan_time" {
				if req.Sorter[i].By == "DESC" {
					m = m.Order(q.ClanTime.Desc())
				} else {
					m = m.Order(q.ClanTime)
				}
			}
			if req.Sorter[i].Field == "create_time" {
				if req.Sorter[i].By == "DESC" {
					m = m.Order(q.CreateTime.Desc())
				} else {
					m = m.Order(q.CreateTime)
				}
			}
		}
	} else {
		m = m.Order(q.ID.Desc())
	}

	req.Page, req.PerPage, offset = forms.CalculatePage(req.Page, req.PerPage)
	count, err := m.Count()
	if err != nil {
		return serializer.Err(consts.CodeParamErr, "查询出错 count", err)
	}
	if req.IsExport == 1 {
		if count > 0 {
			if err = m.Scan(&list); err != nil {
				return serializer.Err(consts.CodeParamErr, "查询出错 lists", err)
			}
			if err := export(ctx, list); err != nil {
				return serializer.Err(consts.CodeParamErr, "生成Excel表错误", err)
			}
		} else {
			return serializer.Err(consts.CodeParamErr, "暂没有要导出的数据", errors.New("暂没有要导出的数据"))
		}
		return serializer.Response{}
	}
	if count > 0 {
		if err = m.Limit(int(req.PerPage)).Offset(int(offset)).Scan(&list); err != nil {
			return serializer.Err(consts.CodeParamErr, "查询出错 list", err)
		}
	}

	retList, err := handlerRet(list)
	if err != nil {
		return serializer.Err(consts.CodeParamErr, "处理数据错误", err)
	}
	listRes := forms.ListRes{
		Page:      req.Page,
		PerPage:   req.PerPage,
		PageCount: (count + req.PerPage - 1) / req.PerPage,
		List:      retList,
	}
	type ret struct {
		forms.ListRes
		Count int64 `json:"count"`
	}
	return serializer.Suc(ret{
		ListRes: listRes,
		Count:   count,
	})
}

func handlerRet(list []model.ChatReportLog) ([]*item, error) {
	layout := "2006010215"
	nowHour := time.Now().Truncate(time.Hour)
	retList := make([]*item, 0, len(list))
	serverMap := make(map[int32]string)
	servers := ServerOption.Option(&gin.Context{})
	for _, server := range servers {
		serverMap[server.Value.(int32)] = server.Name
	}
	delete(serverMap, 0)
	playerServerIDMap := make(map[int64]int32)
	for _, v := range list {
		// 兼容老数据
		if v.ServerID == 0 {
			serverID := playerServerIDMap[v.PlayerID]
			if serverID == 0 {
				if id, err := player.GetDBByUserId(v.PlayerID); err != nil {
					return nil, err
				} else {
					v.ServerID = int32(id)
					playerServerIDMap[v.PlayerID] = serverID
				}
			}
		}
		if v.ClanServerID == 0 {
			serverID := playerServerIDMap[v.ClanPlayerID]
			if serverID == 0 {
				if id, err := player.GetDBByUserId(v.ClanPlayerID); err != nil {
					return nil, err
				} else {
					v.ClanServerID = int32(id)
					playerServerIDMap[v.ClanPlayerID] = serverID
				}
			}
		}
		chatLogs := make([]string, 0)
		day := time.Unix(0, v.ClanTime*int64(time.Millisecond)).Format("20060102")
		beforeHour := time.Unix(0, v.ClanTime*int64(time.Millisecond)).Truncate(time.Hour).Add(-1 * time.Hour).Format(layout)
		chatLogs = append(chatLogs, fmt.Sprintf("%s/%s/chat.%s.log", consts.ServerMap[v.ClanServerID], day, beforeHour))
		clanHour := time.Unix(0, v.ClanTime*int64(time.Millisecond)).Truncate(time.Hour)
		afterClanHour := time.Unix(0, v.ClanTime*int64(time.Millisecond)).Truncate(time.Hour).Add(1 * time.Hour)
		if clanHour.Before(nowHour) {
			hour := clanHour.Format(layout)
			chatLogs = append(chatLogs, fmt.Sprintf("%s/%s/chat.%s.log", consts.ServerMap[v.ClanServerID], day, hour))
		}
		if afterClanHour.Before(nowHour) {
			afterHour := afterClanHour.Format(layout)
			chatLogs = append(chatLogs, fmt.Sprintf("%s/%s/chat.%s.log", consts.ServerMap[v.ClanServerID], day, afterHour))
		}

		serverName := serverMap[v.ServerID]
		clanServerName := serverMap[v.ClanServerID]
		retList = append(retList, &item{
			ChatReportLog:   v,
			ChatLogs:        chatLogs,
			ServerName:      serverName,
			ClanServerName:  clanServerName,
			ClanChannelName: consts.ChannelMap[v.ClanChatChannel],
		})
	}
	return retList, nil
}

type item struct {
	model.ChatReportLog
	ServerName      string   `json:"server_name"`
	ClanServerName  string   `json:"clan_server_name"`
	ClanChannelName string   `json:"clan_channel_name"`
	ChatLogs        []string `json:"chat_logs"`
}

func export(ctx *gin.Context, list []model.ChatReportLog) error {
	lists, err := handlerRet(list)
	if err != nil {
		return err
	}
	// 导出
	f := excelize.NewFile()
	f.SetColWidth("Sheet1", "A", "A", 15)
	f.SetColWidth("Sheet1", "B", "B", 15)
	f.SetColWidth("Sheet1", "C", "C", 15)
	f.SetColWidth("Sheet1", "D", "D", 25)
	f.SetColWidth("Sheet1", "E", "E", 25)
	f.SetColWidth("Sheet1", "F", "F", 30)
	f.SetColWidth("Sheet1", "G", "G", 30)
	f.SetColWidth("Sheet1", "H", "H", 15)
	f.SetColWidth("Sheet1", "J", "J", 15)
	f.SetColWidth("Sheet1", "K", "K", 25)
	f.SetColWidth("Sheet1", "L", "L", 45)
	f.SetColWidth("Sheet1", "M", "M", 25)
	f.SetColWidth("Sheet1", "N", "N", 25)
	// 创建一个工作表
	f.SetCellValue("Sheet1", "A1", "ID")
	f.SetCellValue("Sheet1", "B1", "举报者ID")
	f.SetCellValue("Sheet1", "C1", "举报者昵称")
	f.SetCellValue("Sheet1", "D1", "举报者服务器")
	f.SetCellValue("Sheet1", "E1", "被举报者ID")
	f.SetCellValue("Sheet1", "F1", "被举报者昵称")
	f.SetCellValue("Sheet1", "G1", "被举报者服务器")
	f.SetCellValue("Sheet1", "H1", "举报消息ID")
	f.SetCellValue("Sheet1", "J1", "消息频道")
	f.SetCellValue("Sheet1", "K1", "联盟code")
	f.SetCellValue("Sheet1", "L1", "消息内容")
	f.SetCellValue("Sheet1", "M1", "消息发送时间")
	f.SetCellValue("Sheet1", "N1", "举报时间")

	for i, v := range lists {
		f.SetCellValue("Sheet1", fmt.Sprintf("A%d", i+2), v.ID)

		f.SetCellValue("Sheet1", fmt.Sprintf("B%d", i+2), v.PlayerID)

		f.SetCellValue("Sheet1", fmt.Sprintf("C%d", i+2), v.PlayerName)

		f.SetCellValue("Sheet1", fmt.Sprintf("D%d", i+2), v.ServerName)
		f.SetCellValue("Sheet1", fmt.Sprintf("E%d", i+2), v.ClanPlayerID)
		f.SetCellValue("Sheet1", fmt.Sprintf("F%d", i+2), v.ClanPlayerName)
		f.SetCellValue("Sheet1", fmt.Sprintf("G%d", i+2), v.ClanServerName)
		f.SetCellValue("Sheet1", fmt.Sprintf("H%d", i+2), v.ClanChatID)
		f.SetCellValue("Sheet1", fmt.Sprintf("J%d", i+2), v.ClanChannelName)
		f.SetCellValue("Sheet1", fmt.Sprintf("K%d", i+2), v.LeagueCode)

		f.SetCellValue("Sheet1", fmt.Sprintf("L%d", i+2), v.ClanContent)
		clanTime := time.Unix(0, v.ClanTime*int64(time.Millisecond)).Format("2006-01-02 15:04:05")
		createTime := time.Unix(0, v.CreateTime*int64(time.Millisecond)).Format("2006-01-02 15:04:05")
		f.SetCellValue("Sheet1", fmt.Sprintf("M%d", i+2), clanTime)
		f.SetCellValue("Sheet1", fmt.Sprintf("N%d", i+2), createTime)
	}

	// 设置工作簿的默认工作表
	f.SetActiveSheet(1)
	ctx.Header("Content-Type", "application/vnd.ms-excel")
	ctx.Header("Content-Disposition", fmt.Sprintf("attachment;filename=聊天举报记录导出%s.xlsx", time.Now().Format("20060102150405")))
	f.WriteTo(ctx.Writer)
	return nil
}

func (s *chatReportService) LogList(ctx *gin.Context, req *forms.ChatLogListReq) serializer.Response {
	var (
		q    = query.Use(config.DB).ChatMsgLog
		m    = q.WithContext(ctx)
		list []model.ChatMsgLog
	)
	m = m.Where(q.ChatChannel.Eq(req.ChatChannel))
	if req.ChatChannel != consts.ChatChannel_CrossServer {
		m = m.Where(q.SeverID.Eq(req.ServerID))
	}
	if req.CurrentID != 0 {
		m = m.Where(q.ChatID.Lte(fmt.Sprintf("%d", req.CurrentID))).Order(q.ChatID.Desc())
	}
	if req.BeforeID != 0 {
		m = m.Where(q.ChatID.Lt(fmt.Sprintf("%d", req.BeforeID))).Order(q.ChatID.Desc())
	}
	if req.LaterID != 0 {
		m = m.Where(q.ChatID.Gt(fmt.Sprintf("%d", req.LaterID))).Order(q.ChatID)
	}

	if err := m.Limit(50).Offset(0).Scan(&list); err != nil {
		return serializer.Err(consts.CodeParamErr, "查询出错 list", err)
	}
	if req.CurrentID != 0 || req.BeforeID != 0 {
		// 反转结果
		for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 {
			list[i], list[j] = list[j], list[i]
		}
	}
	return serializer.Suc(list)
}

func (s *chatReportService) DownloadLog(c *gin.Context, req *forms.DownloadChatLogReq) {
	if req.Path == "" {
		c.JSON(http.StatusInternalServerError, gin.H{
			"msg": "参数错误",
		})
		return
	}
	split := strings.Split(req.Path, "/")
	filename := split[len(split)-1]
	response, err := config.GetChatLogCOSClient().Object.Get(c, req.Path, nil)
	defer response.Body.Close()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"msg": "从cos中获取日志文件发生错误:" + err.Error(),
		})
		return
	}

	c.Header("Content-Disposition", "attachment; filename="+filename)
	c.Header("Content-Length", fmt.Sprintf("%d", response.ContentLength))
	c.Header("Content-Type", "application/octet-stream")
	if _, err := io.Copy(c.Writer, response.Body); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"msg": "从cos中获取日志文件发生错误:" + err.Error(),
		})
		return
	}
	c.Status(http.StatusOK)
}

func (s *chatReportService) ChatMsgList(c *gin.Context, req *forms.ChatMsgListReq) serializer.Response {
	var (
		q      = query.Use(config.DB).ChatMsgLog
		m      = q.WithContext(c)
		list   []model.ChatMsgLog
		offset int64 = 0
	)
	if req.ServerID != 0 {
		m = m.Where(q.SeverID.Eq(req.ServerID))
	}

	chatChannelList := make([]int32, 0)
	for _, channel := range req.ChatChannel {
		chatChannelList = append(chatChannelList, channel)
		if channel == 0 {
			chatChannelList = make([]int32, 0)
			break
		}
	}
	if len(chatChannelList) > 0 {
		m = m.Where(q.ChatChannel.In(req.ChatChannel...))
	}

	if req.PlayerID != 0 {
		m = m.Where(q.PlayerID.Eq(req.PlayerID))
	}
	if len(req.CreateTime) == 2 {
		m = m.Where(q.CreateTime.Between(req.CreateTime[0], req.CreateTime[1]))
	}
	req.Page, req.PerPage, offset = forms.CalculatePage(req.Page, req.PerPage)
	count, err := m.Count()
	if err != nil {
		return serializer.Err(consts.CodeParamErr, "查询出错 count", err)
	}
	if count > 0 {
		if err = m.Order(q.ChatID.Desc()).Limit(int(req.PerPage)).Offset(int(offset)).Scan(&list); err != nil {
			return serializer.Err(consts.CodeParamErr, "查询出错 list", err)
		}
	}
	serverMap := make(map[int32]string)
	servers := ServerOption.Option(&gin.Context{})
	for _, server := range servers {
		serverMap[server.Value.(int32)] = server.Name
	}
	delete(serverMap, 0)
	ret := make([]forms.ChatMsgListRet, 0, len(list))
	for _, item := range list {
		ret = append(ret, forms.ChatMsgListRet{
			ID:          item.ID,
			PlayerID:    item.PlayerID,
			NickName:    item.NickName,
			HeadID:      item.HeadID,
			FrameID:     item.FrameID,
			HeadImg:     item.HeadImg,
			CreateTime:  item.CreateTime,
			ChatChannel: item.ChatChannel,
			ChannelName: consts.ChannelMap[item.ChatChannel],
			ChatID:      item.ChatID,
			Content:     item.Content,
			SeverID:     item.SeverID,
			ServerName:  serverMap[item.SeverID],
		})
	}
	listRes := forms.ListRes{
		Page:      req.Page,
		PerPage:   req.PerPage,
		PageCount: (count + req.PerPage - 1) / req.PerPage,
		List:      ret,
	}

	return serializer.Suc(struct {
		forms.ListRes
		Count int64 `json:"count"`
	}{
		ListRes: listRes,
		Count:   count,
	})
}
