package service

import (
	"encoding/json"
	"gadmin/config"
	"gadmin/internal/admin/consts"
	"gadmin/internal/admin/forms"
	"gadmin/internal/gorm/model"
	"gadmin/internal/gorm/query"
	"gadmin/utility"
	"gadmin/utility/serializer"
	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"strings"
)

// Gem 宝石统计服务
var Gem = new(sGem)

type sGem struct{}

type GemReportInfo struct {
	Days       []string `json:"days"`
	Players    []int64  `json:"players"`
	ValidCount []int64  `json:"validCount"`
	Part1      []int64  `json:"part1"`
	Part2      []int64  `json:"part2"`
	Part3      []int64  `json:"part3"`
	Part4      []int64  `json:"part4"`
	Part5      []int64  `json:"part5"`
	Part6      []int64  `json:"part6"`

	AvgPart1 []int64 `json:"avgPart1"`
	AvgPart2 []int64 `json:"avgPart2"`
	AvgPart3 []int64 `json:"avgPart3"`
	AvgPart4 []int64 `json:"avgPart4"`
	AvgPart5 []int64 `json:"avgPart5"`
	AvgPart6 []int64 `json:"avgPart6"`
}

type GemLogItem struct {
	Day        string `json:"days"`
	Players    int64  `json:"players"`
	ValidCount int64  `json:"validCount"`
	Part1      int64  `json:"part1"`
	Part2      int64  `json:"part2"`
	Part3      int64  `json:"part3"`
	Part4      int64  `json:"part4"`
	Part5      int64  `json:"part5"`
	Part6      int64  `json:"part6"`

	AvgPart1 float64 `json:"avgPart1"`
	AvgPart2 float64 `json:"avgPart2"`
	AvgPart3 float64 `json:"avgPart3"`
	AvgPart4 float64 `json:"avgPart4"`
	AvgPart5 float64 `json:"avgPart5"`
	AvgPart6 float64 `json:"avgPart6"`
}

type GemInfo struct {
	Info GemReportInfo `json:"info"`
	Rows []GemLogItem  `json:"rows"`
}

// QueryGemLog 统计宝石信息
func (s *sGem) QueryGemLog(params forms.GemReportReq) (respData GemInfo, err error) {
	var (
		resp GemReportInfo
		rdb  = query.Use(config.DB).ReportDayGem
		rm   = rdb.Select(rdb.ALL, rdb.ID, rdb.Date,
			rdb.PlayerCount.Sum().As("player_count"),
			rdb.Output.Sum().As("output"),
			rdb.Part1.Sum().As("part1"),
			rdb.Part2.Sum().As("part2"),
			rdb.Part3.Sum().As("part3"),
			rdb.Part4.Sum().As("part4"),
			rdb.Part5.Sum().As("part5"),
			rdb.Part6.Sum().As("part6"),
		).Where(rdb.Date.Gte(params.Day), rdb.Date.Lt(params.EndDay))
		b = query.Use(config.DB).ReportDayBasic
	)

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

	result, err := rm.Group(rdb.Date).Order(rdb.Date.Desc()).Find()
	if err != nil {
		return
	}

	for _, v := range result {
		if v != nil {
			// 有效活跃
			var validCount int64
			basic, err := b.Where(b.Date.Eq(utility.ParseDate(v.Date))).First()
			if err == nil && basic != nil {
				validCount = basic.ActiveCount - basic.NewCount + basic.ValidCount
			}
			resp.Days = append(resp.Days, strings.ReplaceAll(v.Date, "T00:00:00+08:00", ""))
			resp.Players = append(resp.Players, v.PlayerCount)
			resp.ValidCount = append(resp.ValidCount, validCount)
			resp.Part1 = append(resp.Part1, v.Part1)
			resp.Part2 = append(resp.Part2, v.Part2)
			resp.Part3 = append(resp.Part3, v.Part3)
			resp.Part4 = append(resp.Part4, v.Part4)
			resp.Part5 = append(resp.Part5, v.Part5)
			resp.Part6 = append(resp.Part6, v.Part6)

			var players int64 = 1
			if v.PlayerCount > 1 {
				players = v.PlayerCount
			}

			resp.AvgPart1 = append(resp.AvgPart1, v.Part1*100/players)
			resp.AvgPart2 = append(resp.AvgPart2, v.Part2*100/players)
			resp.AvgPart3 = append(resp.AvgPart3, v.Part3*100/players)
			resp.AvgPart4 = append(resp.AvgPart4, v.Part4*100/players)
			resp.AvgPart5 = append(resp.AvgPart5, v.Part5*100/players)
			resp.AvgPart6 = append(resp.AvgPart6, v.Part6*100/players)

			item := GemLogItem{
				Day:        strings.ReplaceAll(v.Date, "T00:00:00+08:00", ""),
				Players:    v.PlayerCount,
				ValidCount: validCount,
				Part1:      v.Part1,
				Part2:      v.Part2,
				Part3:      v.Part3,
				Part4:      v.Part4,
				Part5:      v.Part5,
				Part6:      v.Part6,
			}

			item.AvgPart1 = float64(v.Part1*100/players) / 100
			item.AvgPart2 = float64(v.Part2*100/players) / 100
			item.AvgPart3 = float64(v.Part3*100/players) / 100
			item.AvgPart4 = float64(v.Part4*100/players) / 100
			item.AvgPart5 = float64(v.Part5*100/players) / 100
			item.AvgPart6 = float64(v.Part6*100/players) / 100

			respData.Rows = append(respData.Rows, item)

		}
	}
	respData.Info = resp
	return
}

// PartStat 部位统计
func (s *sGem) PartStat(ctx *gin.Context, params forms.GemPartStatReq) serializer.Response {
	var (
		q      = query.Use(config.DB).GemStat
		m      = q.WithContext(ctx)
		m2     = q.WithContext(ctx)
		resp   []*forms.PartStatRow
		models forms.ListRes
		err    error
	)

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

	first, err := m.Order(q.Date.Desc()).First()
	if err != nil {
		return serializer.Err(consts.CodeParamErr, "查询出错 lists", err)
	}

	if first == nil {
		return serializer.Err(consts.CodeParamErr, "查询出错 lists2", err)
	}

	err = m2.Where(q.Date.Eq(first.Date)).Scan(&resp)
	if err != nil {
		return serializer.Err(consts.CodeParamErr, "查询出错 lists3", err)
	}

	for _, v := range resp {
		v.Name = config.GemPartMap[v.Part]
	}

	models.List = resp
	models.Page = 0
	models.PerPage = 1
	models.PageCount = 1

	return serializer.Suc(models)
}

// Stat 综合统计
func (s *sGem) Stat(ctx *gin.Context, params forms.GemStatReq) ([]*forms.StatRow, error) {
	var (
		q              = query.Use(config.DB).ReportDayGem
		m              = q.WithContext(ctx)
		resp           = s.instGemStatRes()
		models         []*model.ReportDayGem
		err            error
		totalPartCount = make(map[int64]int64)
	)

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

	if err = m.Scan(&models); err != nil {
		logrus.Error(err)
		return nil, err
	}

	findIndex := func(part int64, output map[int64]int64) {
		for _, row := range resp {
			if row.Index == part {
				for k, v := range output {
					if row.Level == k {
						row.Count += v
						totalPartCount[part] += v
					}
				}
			}
		}
	}

	partOutput := func(out string) (map[int64]int64, error) {
		var counter = make(map[int64]int64)
		if out == "" || out == "null" {
			return counter, nil
		}
		err = json.Unmarshal([]byte(out), &counter)
		if err != nil {
			logrus.Error(err)
			return nil, err
		}

		return counter, nil
	}

	for _, row := range models {
		var output map[int64]int64
		// 部位1
		output, err := partOutput(row.PartOutput1)
		if err != nil {
			return nil, err
		}
		findIndex(1, output)

		// 部位2
		output, err = partOutput(row.PartOutput2)
		if err != nil {
			return nil, err
		}
		findIndex(2, output)

		// 部位3
		output, err = partOutput(row.PartOutput3)
		if err != nil {
			return nil, err
		}
		findIndex(3, output)

		// 部位4
		output, err = partOutput(row.PartOutput4)
		if err != nil {
			return nil, err
		}
		findIndex(4, output)

		// 部位5
		output, err = partOutput(row.PartOutput5)
		if err != nil {
			return nil, err
		}
		findIndex(5, output)

		// 部位6
		output, err = partOutput(row.PartOutput6)
		if err != nil {
			return nil, err
		}
		findIndex(6, output)
	}

	// 计算占比
	var places int64 = 2
	for _, v := range resp {
		if totalPartCount[v.Index] == 0 {
			v.Ratio = 0
		} else {
			v.Ratio = utility.RoundToFloat(float64(v.Count)/float64(totalPartCount[v.Index])*100, places)
		}

		if v.Level == 0 {
			v.Count = totalPartCount[v.Index]
		}
	}

	return resp, nil
}

// instGemStatRes 初始化综合统计数据结构
func (s *sGem) instGemStatRes() (resp []*forms.StatRow) {
	var (
		parts  = []int64{1, 2, 3, 4, 5, 6}
		levels = []int64{0, 1, 2, 3, 4, 5, 6}
	)

	for _, part := range parts {
		for _, level := range levels {
			resp = append(resp, &forms.StatRow{
				Index: part,
				Name:  config.GemTypeMap[part],
				Level: level,
				Count: 0,
				Ratio: 0,
			})
		}
	}
	return resp
}
