package service

import (
	"fmt"
	"gadmin/config"
	"gadmin/internal/admin/consts"
	"gadmin/internal/admin/forms"
	"gadmin/internal/gorm/model"
	"gadmin/internal/gorm/query"
	"gadmin/package/gmdata"
	"gadmin/utility/player"
	"gadmin/utility/serializer"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/now"
	"github.com/spf13/cast"
	"sort"
	"strings"
	"time"
)

// GrandMaster 最强王者
var GrandMaster = new(sGrandMaster)

type sGrandMaster struct{}

func (s *sGrandMaster) Get(ctx *gin.Context, req forms.GetGrandmasterReq) serializer.Response {
	DB, err := player.GetDBByUserId(req.Playerid)
	if err != nil {
		return serializer.Err(consts.CodeParamErr, "GetDBByUserId err", err)
	}
	var (
		q      = query.Use(config.GDBGroup[DB]).Grandmaster
		m      = q.WithContext(ctx).Where(q.Playerid.Eq(req.Playerid))
		models *model.Grandmaster
	)

	if err = m.Scan(&models); err != nil {
		return serializer.Err(consts.CodeParamErr, "查询出错 ", err)
	}
	return serializer.Suc(models)
}

func (s *sGrandMaster) SetDanScore(ctx *gin.Context, req forms.SetGrandmasterDanScoreReq) serializer.Response {
	/*	var err error
		DB, err := player.GetDBByUserId(req.Playerid)
		if err != nil {
			return serializer.Err(consts.CodeParamErr, err.Error(), err)
		}

		msg := msg2.GmSetDanScore{
			MsgId:      character.GenerateMsgId(),
			PlayerID:   req.Playerid,
			DanScore:   req.DanScore,
			OperatorId: token.GetUID(ctx),
		}

		rpc_share.MsgMap[msg.MsgId] = fmt.Sprintf("GM为修改段位积分 PlayerID: %d, DanScore: %v", req.Playerid, req.DanScore)

		var resp *msg2.ResponseGmSetDanScore
		res, err := config.GmNats.GmRequest(DB, "GmSetDanScore", msg)
		if err != nil {
			return serializer.Err(consts.CodeParamErr, err.Error(), err)
		}

		if err = json.Unmarshal(res, &resp); err != nil {
			return serializer.Err(consts.CodeParamErr, err.Error(), err)
		}

		rpc_share.LogChan <- rpc_share.LogMsg{
			MsgID: msg.MsgId,
			Data:  resp,
		}*/
	return serializer.Suc(req)
}

type GrandMasterReportInfo struct {
	Days    []string `json:"days"`
	Players []int64  `json:"players"`
}

type GrandMasterLogItem struct {
	Day     string `json:"days"`
	Players int64  `json:"players"`
}

type GrandMasterInfo struct {
	Info GrandMasterReportInfo `json:"info"`
	Rows []GrandMasterLogItem  `json:"rows"`
}

type ReportDayGrandMaster struct {
	model.ReportDayGrandmaster
}

// QueryLog 统计报表
func (s *sGrandMaster) QueryLog(params forms.GrandmasterReportReq) (result []*ReportDayGrandMaster, err error) {
	rdb := query.Use(config.DB).ReportDayGrandmaster
	m := rdb.Where(rdb.Date.Gte(params.Day), rdb.Date.Lt(params.EndDay)).Order(rdb.Date.Desc())

	switch params.ChannelId {
	case consts.ChannelIdNone:
		// 不选择渠道
	case consts.ChannelIdAllAdv, consts.ChannelIdAllWx, consts.ChannelIdAllTT:
		// 所有的广告渠道
		m = m.Where(rdb.ChannelID.In(Channel.GetIdsByType(params.ChannelId)...))
	default:
		// 指定渠道
		m = m.Where(rdb.ChannelID.Eq(params.ChannelId))
	}

	if params.ServerId > 0 {
		m = m.Where(rdb.ServerID.Eq(int32(params.ServerId)))
	}

	distributes, err := m.Find()
	if err != nil {
		return
	}

	add := func(row *model.ReportDayGrandmaster) {
		var exist bool
		for _, v := range result {
			if v.Date == row.Date {
				exist = true
				v.PlayerCount += row.PlayerCount
				v.OpenPlayerCount += row.OpenPlayerCount
				v.PartCount += row.PartCount
				v.AllMatchSeconds += row.AllMatchSeconds
				v.BattleWavesCount += row.BattleWavesCount
				v.AllBattleSeconds += row.AllBattleSeconds
				v.LeaveUsers += row.LeaveUsers
			}
		}

		if exist == false {
			v := new(ReportDayGrandMaster)
			v.Date = row.Date
			v.ChannelID = row.ChannelID
			v.PlayerCount += row.PlayerCount
			v.OpenPlayerCount += row.OpenPlayerCount
			v.PartCount += row.PartCount
			v.AllMatchSeconds += row.AllMatchSeconds
			v.BattleWavesCount += row.BattleWavesCount
			v.AllBattleSeconds += row.AllBattleSeconds
			v.LeaveUsers += row.LeaveUsers
			result = append(result, v)
		}
	}

	for _, distribute := range distributes {
		add(distribute)
	}

	for _, v := range result {
		v.Date = strings.ReplaceAll(v.Date, "T00:00:00+08:00", "")
	}
	return
}

type GrandmasterWaves struct {
	Waves int   `json:"waves"`
	Total int64 `json:"total"`
}

func (s *sGrandMaster) Waves(params forms.GrandmasterWavesReq) (results []GrandmasterWaves, err error) {
	key := config.UKey("GrandmasterWaves", params)
	if err = config.GetCacheScan(key, &results); err != nil {
		return
	}

	if len(results) != 0 {
		return
	}

	var (
		grandMasterModel = &model.GrandmasterLog{}
		m                = config.DB.Model(&model.GrandmasterLog{}).Scopes(model.TableOfYearMonth(grandMasterModel.TableName(), time.Now())).
					Select("battle_waves as waves, COUNT(*) AS total").
					Where("event_id in(4,5) and date = ? and `battle_waves` BETWEEN ? AND ?",
				time.Unix(params.Date/1000, 0).Format("2006-01-02"), params.StartWaves, params.EndWaves)
	)

	if params.ServerId > 0 {
		m = m.Where("server_id = ?", params.ServerId)
	}

	m.Group("battle_waves").Scan(&results)

	results = s.completeMissingLevels(params, results)

	if len(results) > 0 {
		config.SetCache(key, results, now.BeginningOfDay().Unix()+86400)
	}
	return
}

func (s *sGrandMaster) completeMissingLevels(params forms.GrandmasterWavesReq, results []GrandmasterWaves) []GrandmasterWaves {
	var completedResults []GrandmasterWaves
	levels := make(map[int]bool)

	for _, result := range results {
		levels[result.Waves] = true
		completedResults = append(completedResults, result)
	}

	for i := params.StartWaves; i <= params.EndWaves; i++ {
		if !levels[int(i)] {
			completedResults = append(completedResults, GrandmasterWaves{Waves: int(i), Total: 0})
		}
	}

	sort.Slice(completedResults, func(i, j int) bool {
		return completedResults[i].Waves < completedResults[j].Waves // 根据等级从小到大排序
	})
	return completedResults
}

type GrandmasterSeconds struct {
	Seconds int   `json:"seconds"`
	Total   int64 `json:"total"`
}

func (s *sGrandMaster) Seconds(params forms.GrandmasterSecondsReq) (results []GrandmasterSeconds, err error) {
	key := config.UKey("GrandmasterSeconds", params)
	if err = config.GetCacheScan(key, &results); err != nil {
		return
	}

	if len(results) != 0 {
		return
	}

	var (
		grandMasterModel = &model.GrandmasterLog{}
		m                = config.DB.Model(&model.GrandmasterLog{}).Scopes(model.TableOfYearMonth(grandMasterModel.TableName(), time.Now())).
					Select("battle_seconds as seconds, COUNT(*) AS total").
					Where("event_id in(4,5) and date = ? and `battle_seconds` BETWEEN ? AND ?",
				time.Unix(params.Date/1000, 0).Format("2006-01-02"), params.StartSeconds, params.EndSeconds)
	)

	if params.ServerId > 0 {
		m = m.Where("server_id = ?", params.ServerId)
	}

	m.Group("battle_seconds").Scan(&results)

	results = s.completeMissingSeconds(params, results)

	if len(results) > 0 {
		config.SetCache(key, results, now.BeginningOfDay().Unix()+86400)
	}
	return
}

func (s *sGrandMaster) completeMissingSeconds(params forms.GrandmasterSecondsReq, results []GrandmasterSeconds) []GrandmasterSeconds {
	var completedResults []GrandmasterSeconds
	levels := make(map[int]bool)

	for _, result := range results {
		levels[result.Seconds] = true
		completedResults = append(completedResults, result)
	}

	for i := params.StartSeconds; i <= params.EndSeconds; i++ {
		if !levels[int(i)] {
			completedResults = append(completedResults, GrandmasterSeconds{Seconds: int(i), Total: 0})
		}
	}

	sort.Slice(completedResults, func(i, j int) bool {
		return completedResults[i].Seconds < completedResults[j].Seconds // 根据等级从小到大排序
	})
	return completedResults
}

type GrandmasterDan struct {
	DanID   int    `json:"id"`
	DanName string `json:"danName"`
	Total   int64  `json:"total"`
}

type ByDanID []*GrandmasterDan

func (a ByDanID) Len() int           { return len(a) }
func (a ByDanID) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByDanID) Less(i, j int) bool { return a[i].DanID < a[j].DanID }

func (s *sGrandMaster) Dan(params forms.GrandmasterDanReq) (results []*GrandmasterDan, err error) {
	key := config.UKey("GrandmasterDan", params)
	if err = config.GetCacheScan(key, &results); err != nil {
		return
	}

	if len(results) != 0 {
		return
	}

	type Log struct {
		UserID int
		Score  int64
	}

	var logs []*Log
	grandMasterModel := &model.GrandmasterLog{}
	tableName := fmt.Sprintf("%s_%s", grandMasterModel.TableName(), time.Now().Format("200601"))
	if !config.DB.Migrator().HasTable(tableName) {
		tableName = grandMasterModel.TableName()
	}
	subQuery := `(SELECT user_id, MAX(event_at) AS last_event_at FROM %s where date = '%v' and event_id = 5`
	subQuery = fmt.Sprintf(subQuery, tableName, time.Unix(params.Date/1000, 0).Format("2006-01-02"))

	if params.ServerId > 0 {
		subQuery += " and server_id = " + cast.ToString(params.ServerId)
	}

	subQuery += ` GROUP BY user_id) AS B`

	joins := "INNER JOIN " + subQuery + " ON A.user_id = B.user_id AND A.event_at = B.last_event_at and A.date = '%v' and A.event_id = 5"
	joins = fmt.Sprintf(joins, time.Unix(params.Date/1000, 0).Format("2006-01-02"))

	if params.ServerId > 0 {
		joins += " and A.server_id = " + cast.ToString(params.ServerId)
	}

	joins += ` GROUP BY user_id, dan_score`

	query1 := config.DB.Table(fmt.Sprintf("%s as A", tableName)).Select("A.user_id, A.dan_score as score").Joins(joins).Scan(&logs)
	if query1.Error != nil {
		return nil, query1.Error
	}

	if len(logs) == 0 {
		results = make([]*GrandmasterDan, 0)
		return
	}

	addResult := func(dan *gmdata.KingSeasonDan) {
		for i, v := range results {
			if v.DanID == dan.Id {
				results[i].Total++
				return
			}
		}

		results = append(results, &GrandmasterDan{
			DanID:   dan.Id,
			DanName: dan.DanName,
			Total:   1,
		})
	}

	for _, v := range logs {
		dan := gmdata.GetDanByScore(v.Score)
		if dan == nil {
			continue
		}
		addResult(dan)
	}
	sort.Sort(ByDanID(results))

	if len(results) > 0 {
		config.SetCache(key, results, now.BeginningOfDay().Unix()+86400)
	}
	return
}

type GrandmasterMatch struct {
	Seconds int64 `json:"seconds"`
	Total   int64 `json:"total"`
}

func (s *sGrandMaster) Match(params forms.GrandmasterMatchReq) (results []*GrandmasterMatch, err error) {
	//key := config.UKey("GrandmasterMatch", params)
	//if err = config.GetCacheScan(key, &results); err != nil {
	//	return
	//}
	//
	//if len(results) != 0 {
	//	return
	//}

	var (
		m = config.DB.Model(&model.GrandmasterMatch{}).
			Select("seconds, times AS total").
			Where("type = ?", params.Type).
			Where("`seconds` BETWEEN ? AND ?", params.StartSeconds, params.EndSeconds)
	)

	m.Scan(&results)

	results = s.completeMissingMatch(params, results)

	//if len(results) > 0 {
	//	config.SetCache(key, results, now.BeginningOfDay().Unix()+86400)
	//}
	return
}

func (s *sGrandMaster) completeMissingMatch(params forms.GrandmasterMatchReq, results []*GrandmasterMatch) []*GrandmasterMatch {
	var completedResults []*GrandmasterMatch
	levels := make(map[int]bool)

	for _, result := range results {
		levels[int(result.Seconds)] = true
		completedResults = append(completedResults, result)
	}

	for i := params.StartSeconds; i <= params.EndSeconds; i++ {
		if !levels[int(i)] {
			completedResults = append(completedResults, &GrandmasterMatch{Seconds: int64(i), Total: 0})
		}
	}

	sort.Slice(completedResults, func(i, j int) bool {
		return completedResults[i].Seconds < completedResults[j].Seconds // 根据等级从小到大排序
	})
	return completedResults
}
