package jobs

import (
	"context"
	"encoding/json"
	"fmt"
	"gadmin/config"
	"gadmin/internal/admin/service"
	"gadmin/internal/gorm/query"
	"gadmin/utility"
	"gadmin/utility/player"
	"github.com/jinzhu/now"
	"github.com/sirupsen/logrus"
	"os"
	"strings"
	"sync"
	"time"
)

var (
	HaveRoles = new(jHaveRoles)
)

type jHaveRoles struct {
	ctx context.Context
	sync.RWMutex
}

type HaveRolesNums struct {
	RoleNums int64 `json:"role_nums"`
	Count    int64 `json:"count"`
}

func (j *jHaveRoles) Run() {
	j.ctx = context.TODO()
	logrus.Info("jHaveRoles Run.....")
	if os.Getenv("GIN_MODE") == "release" || os.Getenv("ADMIN_IS_LOCAL") == "1" {
		yesterday := now.With(time.Now().AddDate(0, 0, -1))
		for serverId, _ := range config.GDBGroup {
			j.haveRoles(serverId, yesterday)
		}
	} else {
		logrus.Warn("非正式环境无需进行，跳过..")
	}
}

func (j *jHaveRoles) RunWithDate(date *now.Now) {
	j.ctx = context.TODO()
	logrus.Info("jHaveRoles RunWithDate.....")
	if os.Getenv("GIN_MODE") == "release" || os.Getenv("ADMIN_IS_LOCAL") == "1" {
		for serverId, _ := range config.GDBGroup {
			j.haveRoles(serverId, date)
		}
	} else {
		logrus.Warn("非正式环境无需进行，跳过..")
	}
}

func (j *jHaveRoles) haveRoles(serverId int, yesterday *now.Now) {
	j.RLock()
	defer j.RUnlock()

	DB, err := player.GetDBByServerID(serverId)
	if err != nil {
		logrus.Warningf("haveRoles GetDBByServerID，err：%v", err)
		return
	}

	var (
		allHaveRoles = make(map[string]map[int64]int64)
		date         = utility.Format(yesterday.Time)
		endUnix      = yesterday.EndOfDay().Unix()
	)
	logrus.Infof("统计拥有角色数据，date：%v, Unix:%+v", date, endUnix)

	channelIds, err := service.Channel.Ids()
	if err != nil {
		logrus.Warningf("Channel.Ids，err：%v", err)
		return
	}

	allHaveRoles["-1"] = make(map[int64]int64)
	for _, channelId := range channelIds {
		if allHaveRoles[channelId] == nil {
			allHaveRoles[channelId] = make(map[int64]int64)
		}

		if channelId == "0" {
			continue
		}
		tmpIds := service.PlayerChannel.PlayerIds(j.ctx, channelId)
		pIds := utility.SpiltInt64BySizeFromInt64(tmpIds, 10000)
		for _, ids := range pIds {
			roleNums, err := j.GetRoleNums(DB, ids, endUnix)
			if err != nil {
				logrus.Warningf("GetRoleNums，err：%v", err)
				return
			}

			if len(roleNums) == 0 {
				continue
			}

			for _, roleNum := range roleNums {
				allHaveRoles[channelId][roleNum.RoleNums] += roleNum.Count
				allHaveRoles["-1"][roleNum.RoleNums] += roleNum.Count
			}

		}
	}

	allRoleNums, err := j.GetRoleNums(DB, []int64{}, endUnix)
	if err != nil {
		logrus.Warningf("GetRoleNums all，err：%v", err)
		return
	}

	if len(allRoleNums) == 0 {
		// 设置默认值
		allHaveRoles["0"][1] = 0
	} else {
		for _, roleNum := range allRoleNums {
			allHaveRoles["0"][roleNum.RoleNums] += roleNum.Count - allHaveRoles["-1"][roleNum.RoleNums]
		}
	}

	for channelId, haveRoles := range allHaveRoles {
		if channelId == "-1" {
			continue
		}

		str, err := json.Marshal(haveRoles)
		if err != nil {
			logrus.Errorf("ReportDayHaveRole Save Marshal err:%+v", err)
			return
		}

		reportDao := query.Use(config.DB).ReportDayHaveRole // 统计表
		arl, _ := reportDao.Where(reportDao.Date.Eq(date), reportDao.ChannelID.Eq(channelId), reportDao.ServerID.Eq(int32(serverId))).FirstOrInit()
		arl.Date = date
		arl.ChannelID = channelId
		arl.ServerID = int32(serverId)
		arl.Data = string(str)
		if err = reportDao.Save(arl); err != nil {
			logrus.Errorf("ReportDayHaveRole Save err:%+v", err)
			return
		}
	}

	logrus.Info("统计拥有角色数据完成..")
}

func (j *jHaveRoles) GetRoleNums(DB int, ids []int64, endStamp int64) (result []*HaveRolesNums, err error) {
	if endStamp <= 0 {
		endStamp = now.With(time.Now().AddDate(0, 0, -1)).EndOfDay().Unix()
	}

	endStr := time.Unix(endStamp, 0).Format("2006-01-02 15:04:05")

	// 存在条件
	if len(ids) > 0 {
		idStr := strings.Trim(strings.Replace(fmt.Sprint(ids), " ", ",", -1), "[]")
		tx := config.GDBGroup[DB].
			Raw(fmt.Sprintf("select b.role_nums, count(1) as count from (SELECT ua.playerid, floor(length(pm.roles)/27) as role_nums FROM player_attr ua left join player_material pm on ua.playerid = pm.playerid where ua.playerid in (%v) and  ua.create_time <= '%v' and pm.roles is not null) b group by b.role_nums",
				idStr, endStr))
		if err = tx.Scan(&result).Error; err != nil {
			return nil, err
		}
		return
	}

	tx := config.GDBGroup[DB].
		Raw(fmt.Sprintf("select b.role_nums, count(1) as count from (SELECT ua.playerid, floor(length(pm.roles)/27) as role_nums FROM player_attr ua left join player_material pm on ua.playerid = pm.playerid where ua.create_time <= '%v' and pm.roles is not null) b group by b.role_nums", endStr))
	if err = tx.Scan(&result).Error; err != nil {
		return nil, err
	}

	return
}
