package v1

import (
	"designs/app/common/request"
	"designs/app/common/response"
	"designs/global"
	"designs/model"
	"designs/utils"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/pkg/errors"
	"sort"
	"strconv"
	"strings"
	"time"
)

func UserActionList(c *gin.Context) {
	form := request.Check(c, &struct {
		Gid string `form:"gid" binding:"required"`
		//Pf        []string `form:"pf" binding:""`
		StartTime string `form:"startTime" binding:"required"`
		EndTime   string `form:"endTime" binding:"required"`
	}{})

	form.EndTime = form.EndTime + " 23:59:59"

	//查询出所有的事件
	var actionList []model.GameAction

	query := global.App.DB.Table("game_action")

	err := query.
		Where("gid", form.Gid).
		Select("id", "actionId", "actionName").
		Order("id desc").Scan(&actionList).Error
	if err != nil {
		response.Fail(c, 1003, err.Error())
		return
	}

	var optionIdList []int
	for _, v := range actionList {
		optionIdList = append(optionIdList, v.ID)
	}

	//查询出有无选项
	var optionIdList1 []int
	err = global.App.DB.Table("game_action_option").
		WhereIn("actionId", optionIdList).
		Distinct("actionId").
		Pluck("actionId", &optionIdList1).Error
	if err != nil {
		response.Fail(c, 1003, err.Error())
		return
	}

	//查出用户登录数据
	userLogin, err := GetUserLogin(form.Gid, form.StartTime, form.EndTime)
	userLoginCount := len(userLogin)

	//查询出时间段内事件触发数量，以及触发人的ID
	var userAction []model.UserAction
	query2 := global.App.DB.Table("user_action")
	//if len(form.Pf) > 0 {
	//	query2 = query2.WhereIn("pf", form.Pf)
	//}
	err = query2.
		Where("gid", form.Gid).
		Where("createdAt", ">=", form.StartTime).
		Where("createdAt", "<=", form.EndTime).
		Select("id", "actionId", "userId", "createdAt").
		Scan(&userAction).Error
	if err != nil {
		response.Fail(c, 1002, err.Error())
		return
	}
	//计算事件的触发总数和触发用户数
	actionSumMap := make(map[string]int)
	actionUserSumMap := make(map[string]map[int]bool)

	for _, action := range userAction {
		if actionUserSumMap[action.ActionId] == nil {
			actionUserSumMap[action.ActionId] = make(map[int]bool)
		}
		actionSumMap[action.ActionId]++
		actionUserSumMap[action.ActionId][action.UserId] = true
	}

	//根据事件触发和活跃用户数量进行比对得出其他数据
	activeUser := make(map[int]bool)
	var activeUserSlice []int
	for _, users := range userLogin {
		activeUser[users.UserId] = true
	}
	for k := range activeUser {
		activeUserSlice = append(activeUserSlice, k)
	}

	type responses struct {
		Id              int     `json:"id"`
		ActionId        string  `json:"actionId"`
		ActionName      string  `json:"actionName"`
		ActionCount     int     `json:"actionCount"`
		ActionUserCount int     `json:"actionUserCount"`
		ActiveUserRate  float64 `json:"activeUserRate"`
		LoginActiveRate float64 `json:"loginActiveRate"`
		HaveOption      bool    `json:"haveOption"`
	}

	var res []responses
	for _, v := range actionList {
		var ActiveUserRate float64
		var LoginActiveRate float64
		if userLoginCount > 0 {
			ActiveUserRate = DivideWithPrecision(actionSumMap[v.ActionId], userLoginCount)
			LoginActiveRate = DivideWithPrecision(len(actionUserSumMap[v.ActionId]), userLoginCount)
		}

		res = append(res, responses{
			Id:              v.ID,
			ActionId:        v.ActionId,
			ActionName:      v.ActionName,
			ActionCount:     actionSumMap[v.ActionId],
			ActionUserCount: len(actionUserSumMap[v.ActionId]),
			ActiveUserRate:  ActiveUserRate,
			LoginActiveRate: LoginActiveRate,
			HaveOption:      utils.InArray(v.ID, optionIdList1),
		})
	}

	response.Success(c, gin.H{
		"data":  res,
		"count": len(res),
	})
}

func GetUserLogin(Gid string, StartTime string, EndTime string) ([]model.UserLogin, error) {
	//查询出时间段内的活跃用户,登录次数
	var userLogin []model.UserLogin
	query1 := global.App.DB.Table("user_login")
	//if len(form.Pf) > 0 {
	//	query1 = query1.WhereIn("pf", form.Pf)
	//}
	err := query1.
		Where("gid", Gid).
		Where("loginTime", ">=", StartTime).
		Where("loginTime", "<=", EndTime).
		Select("userId", "loginTime").
		Distinct("userId").
		Scan(&userLogin).Error
	if err != nil {
		return userLogin, err
	}

	return userLogin, nil
}

func UserActionOptionList(c *gin.Context) {
	form := request.Check(c, &struct {
		Gid       string `form:"gid" binding:"required"`
		ActionId  string `form:"actionId" binding:"required"`
		StartTime string `form:"startTime" binding:"required"`
		EndTime   string `form:"endTime" binding:"required"`
	}{})

	form.EndTime = form.EndTime + " 23:59:59"

	now := time.Now()
	//查出用户登录数据
	userLogin, err := GetUserLogin(form.Gid, form.StartTime, form.EndTime)
	if err != nil {
		response.Fail(c, 1003, err.Error())
		return
	}

	fmt.Println(time.Since(now))
	userLoginCount := len(userLogin)
	//查询出所有的事件选项
	var actionOption []struct {
		model.UserActionOption
		UserId int `json:"userId" gorm:"not null;column:userId;"`
	}

	err = global.App.DB.Table("user_action_option").
		LeftJoin("user_action", "user_action.id = user_action_option.UserActionId").
		Where("user_action.actionId", form.ActionId).
		Where("user_action.gid", form.Gid).
		Where("user_action.createdAt", ">=", form.StartTime).
		Where("user_action.createdAt", "<=", form.EndTime).
		Select("user_action_option.*", "user_action.userId").
		Scan(&actionOption).Error
	if err != nil {
		response.Fail(c, 1004, err.Error())
		return
	}
	fmt.Println(time.Since(now))
	//循环得出选项
	optionList := make(map[string]int)
	for _, v := range actionOption {
		optionList[v.OptionId+"|"+v.Value]++
	}

	//根据人数进行比对
	//计算事件的触发总数和触发用户数
	actionSumMap := make(map[string]int)
	actionUserSumMap := make(map[string]map[int]bool)

	for _, action := range actionOption {
		if actionUserSumMap[action.OptionId+"|"+action.Value] == nil {
			actionUserSumMap[action.OptionId+"|"+action.Value] = make(map[int]bool)
		}
		actionSumMap[action.OptionId+"|"+action.Value]++
		actionUserSumMap[action.OptionId+"|"+action.Value][action.UserId] = true
	}

	//根据事件触发和活跃用户数量进行比对得出其他数据
	activeUser := make(map[int]bool)
	var activeUserSlice []int
	for _, users := range userLogin {
		activeUser[users.UserId] = true
	}
	for k := range activeUser {
		activeUserSlice = append(activeUserSlice, k)
	}

	type responses struct {
		Id              int     `json:"id"`
		ActionId        int     `json:"actionId"`
		ActionName      string  `json:"actionName"`
		ActionCount     int     `json:"actionCount"`
		ActionUserCount int     `json:"actionUserCount"`
		ActiveUserRate  float64 `json:"activeUserRate"`
		LoginActiveRate float64 `json:"loginActiveRate"`
	}

	var res []responses

	var optionName []model.GameActionOption
	optionIdToName := make(map[string]string)
	global.App.DB.Table("game_action_option").
		LeftJoin("game_action", "game_action.id = game_action_option.actionId").
		Where("gid", form.Gid).Scan(&optionName)
	for _, v := range optionName {
		optionIdToName[v.OptionId] = v.OptionName
	}
	fmt.Println(time.Since(now))
	for k, v := range optionList {
		var ActiveUserRate float64
		var LoginActiveRate float64
		if userLoginCount > 0 {
			ActiveUserRate = DivideWithPrecision(actionSumMap[k], userLoginCount)
			LoginActiveRate = DivideWithPrecision(len(actionUserSumMap[k]), userLoginCount)
		}

		optionId := strings.Split(k, "|")[0]
		value := strings.Split(k, "|")[1]
		valueInt, _ := strconv.Atoi(value)

		res = append(res, responses{
			ActionId:        valueInt,
			ActionName:      optionIdToName[optionId] + ":" + value,
			ActionCount:     v,
			ActionUserCount: len(actionUserSumMap[k]),
			ActiveUserRate:  ActiveUserRate,
			LoginActiveRate: LoginActiveRate,
		})
	}

	sort.Slice(res, func(i, j int) bool {
		return res[i].ActionId < res[j].ActionId // 正序规则：i的Age小于j时返回true
	})

	response.Success(c, gin.H{
		"data":  res,
		"count": len(res),
	})
}

func DivideWithPrecision(a, b int) float64 {
	if b == 0 {
		panic("除数不能为零") // 实际项目中建议返回 error 类型
	}
	// 转换为浮点数再相除
	result := float64(a) / float64(b)
	// 格式化为三位小数并转换回 float64
	formatted, _ := strconv.ParseFloat(fmt.Sprintf("%.3f", result), 64)
	return formatted
}

func UserActionDetail(c *gin.Context) {
	form := request.Check(c, &struct {
		Id        int      `form:"id" binding:"required"`
		Pf        []string `form:"pf" binding:""`
		StartTime string   `form:"startTime" binding:"required"`
		EndTime   string   `form:"endTime" binding:"required"`
	}{})

	//查询启动次数
	var action model.GameAction
	err := global.App.DB.Table("game_action").
		Where("id", form.Id).Find(&action).Error
	if err != nil {
		response.Fail(c, 1001, err.Error())
		return
	}
	var userAction []struct {
		UserId    int    `json:"userId" gorm:"not null;column:userId;"`
		CreatedAt string `json:"createdAt" gorm:"not null;column:createdAt;"`
	}
	err = global.App.DB.Table("user_action").
		Where("gid", action.Gid).
		Where("actionId", action.ActionId).
		Select("userId", "DATE_FORMAT(createdAt, '%Y-%m-%d') as createdAt").
		Scan(&userAction).Error
	if err != nil {
		response.Fail(c, 1002, err.Error())
		return
	}

	//查询出时间段内的活跃用户,登录次数
	var userLogin []struct {
		UserId    int    `json:"userId" gorm:"not null;column:userId;"`
		CreatedAt string `json:"createdAt" gorm:"not null;column:createdAt;"`
	}
	err = global.App.DB.Table("user_login").
		Where("gid", action.Gid).
		Where("loginTime", ">=", form.StartTime).
		Where("loginTime", "<=", form.EndTime).
		Select("userId", "DATE_FORMAT(loginTime, '%Y-%m-%d') as createdAt").
		Scan(&userLogin).Error
	if err != nil {
		response.Fail(c, 1001, err.Error())
		return
	}
	//userLoginCount := len(userLogin)

	activeCount := make(map[string]int)
	activeCountUser := make(map[string]map[int]bool)

	//根据日期进行分组
	for _, v := range userAction {
		activeCount[v.CreatedAt]++

		if activeCountUser[v.CreatedAt] == nil {
			activeCountUser[v.CreatedAt] = make(map[int]bool)
		}
		activeCountUser[v.CreatedAt][v.UserId] = true

	}

	days := utils.GetTimeDayDateFormat(form.StartTime, form.EndTime)

	type responses struct {
		Date            string  `json:"date"`
		ActiveCount     int     `json:"activeCount"`
		ActiveUserCount int     `json:"activeUserCount"`
		ActiveCountRate float64 `json:"activeCountRate"`
		ActiveCountUser float64 `json:"activeCountUser"`
	}
	var res []responses
	//输出格式
	for _, v := range days {
		res = append(res, responses{
			Date:            v,
			ActiveCount:     activeCount[v],
			ActiveUserCount: len(activeCountUser[v]),
			ActiveCountRate: float64(activeCount[v] / 1),
			ActiveCountUser: float64(len(activeCountUser[v]) / 1),
		})
	}

	response.Success(c, gin.H{
		"data": res,
	})
}

func UserActionDetailDistribution(c *gin.Context) {
	form := request.Check(c, &struct {
		Id        int      `form:"id" binding:"required"`
		Pf        []string `form:"pf" binding:""`
		StartTime string   `form:"startTime" binding:"required"`
		EndTime   string   `form:"endTime" binding:"required"`
		Type      int      `form:"type" binding:"required"`
	}{})

	var action model.GameAction
	err := global.App.DB.Table("game_action").
		Where("id", form.Id).Find(&action).Error
	if err != nil {
		response.Fail(c, 1001, err.Error())
		return
	}

	res := make(map[string]interface{})
	if form.Type == 1 {
		var userAction []struct {
			UserId    int    `json:"userId" gorm:"not null;column:userId;"`
			CreatedAt string `json:"createdAt" gorm:"not null;column:createdAt;"`
		}
		query := global.App.DB.Table("user_action")
		if len(form.Pf) > 0 {
			query = query.WhereIn("pf", form.Pf)
		}
		err = query.
			Where("gid", action.Gid).
			Where("actionId", action.ActionId).
			Select("userId", "DATE_FORMAT(createdAt, '%Y-%m-%d') as createdAt").
			Scan(&userAction).Error
		if err != nil {
			response.Fail(c, 1002, err.Error())
			return
		}

		activeCount := make(map[string]int)
		for _, v := range userAction {
			activeCount[v.CreatedAt]++
		}

		days := utils.GetTimeDayDateFormat(form.StartTime, form.EndTime)
		for _, v := range days {
			res[v] = activeCount[v]
		}

		response.Success(c, gin.H{
			"data": map[string]interface{}{
				"avg":  fmt.Sprintf("%.2f", float64(len(userAction))/float64(len(days))),
				"list": res,
			},
		})

	} else if form.Type == 2 {
		var userAction []struct {
			UserId    int    `json:"userId" gorm:"not null;column:userId;"`
			CreatedAt string `json:"createdAt" gorm:"not null;column:createdAt;"`
		}
		query := global.App.DB.Table("user_action")
		if len(form.Pf) > 0 {
			query = query.WhereIn("gid", form.Pf)
		}
		err = query.
			Where("gid", action.Gid).
			Where("actionId", action.ActionId).
			Select("userId", "DATE_FORMAT(createdAt, '%Y-%m-%d') as createdAt").
			Scan(&userAction).Error
		if err != nil {
			response.Fail(c, 1002, err.Error())
			return
		}

		activeCount := make(map[string]map[int]bool)
		for _, v := range userAction {
			if activeCount[v.CreatedAt] == nil {
				activeCount[v.CreatedAt] = make(map[int]bool)
			}
			activeCount[v.CreatedAt][v.UserId] = true
		}

		days := utils.GetTimeDayDateFormat(form.StartTime, form.EndTime)
		for _, v := range days {
			res[v] = len(activeCount[v])
		}

		response.Success(c, gin.H{
			"data": map[string]interface{}{
				"avg":  fmt.Sprintf("%.2f", float64(len(userAction))/float64(len(days))),
				"list": res,
			},
		})
	} else if form.Type == 3 {
		//活跃设备发生率
		var userAction []string
		query := global.App.DB.Table("user_action")
		if len(form.Pf) > 0 {
			query = query.WhereIn("pf", form.Pf)
		}
		err = query.
			Where("gid", action.Gid).
			Where("actionId", action.ActionId).
			Pluck("DATE_FORMAT(createdAt, '%Y-%m-%d') as createdAt", &userAction).Error
		if err != nil {
			response.Fail(c, 1002, err.Error())
			return
		}
		actionCount := make(map[string]int)
		for _, v := range userAction {
			actionCount[v]++
		}

		//var userOnline model.UserOnline
		//query = global.App.DB.Table("user_online")
		//if len(form.Pf) > 0 {
		//	query = query.WhereIn("gid", form.Pf)
		//}
		//err = query.
		//	Where("gid", action.Gid).
		//	Error
		//if err != nil {
		//	response.Fail(c, 1002, err.Error())
		//	return
		//}
		//userCount := make(map[string]map[int]bool)
		//for _, v := range userOnline {
		//
		//}

	} else if form.Type == 4 {
		//每次启动发生率
		var userLogin []string
		query := global.App.DB.Table("user_login")
		if len(form.Pf) > 0 {
			query = query.WhereIn("pf", form.Pf)
		}
		err = query.
			Where("gid", action.Gid).
			Pluck("DATE_FORMAT(createdAt, '%Y-%m-%d') as createdAt", &userLogin).Error
		if err != nil {
			response.Fail(c, 1001, err.Error())
			return
		}
		loginCount := make(map[string]int)
		for _, v := range userLogin {
			loginCount[v]++
		}
		var userAction []string
		query = global.App.DB.Table("user_action")
		if len(form.Pf) > 0 {
			query = query.WhereIn("pf", form.Pf)
		}
		err = query.
			Where("gid", action.Gid).
			Where("actionId", action.ActionId).
			Pluck("DATE_FORMAT(createdAt, '%Y-%m-%d') as createdAt", &userAction).Error
		if err != nil {
			response.Fail(c, 1002, err.Error())
			return
		}
		actionCount := make(map[string]int)
		for _, v := range userAction {
			actionCount[v]++
		}
		days := utils.GetTimeDayDateFormat(form.StartTime, form.EndTime)
		for _, v := range days {
			if loginCount[v] > 0 {
				res[v] = float64(actionCount[v]) / float64(loginCount[v])
			} else {
				res[v] = 0
			}
		}

	} else {
		response.Fail(c, 1003, errors.New("type 错误"))
		return
	}
}

func CopyGameAction(c *gin.Context) {
	form := request.Check(c, &struct {
		Gid    string `form:"gid" binding:"required"`
		NewGid string `form:"newGid" binding:"required"`
	}{})

	//读取出gid对应的配置
	var gameAction []model.GameAction
	global.App.DB.Table("game_action").Where("gid", form.Gid).Scan(&gameAction)

	now := model.XTime{
		Time: time.Now(),
	}

	for _, v := range gameAction {
		//复制
		newAction := model.GameAction{
			Gid:        form.NewGid,
			ActionId:   v.ActionId,
			ActionName: v.ActionName,
			Status:     v.Status,
			Remark:     v.Remark,
			CreatedAt:  now,
			UpdatedAt:  now,
		}

		global.App.DB.Table("game_action").Create(&newAction)

		//查询出有无对应的option
		var actionOption []model.GameActionOption
		global.App.DB.Table("game_action_option").Where("actionId", v.ID).Scan(&actionOption)
		fmt.Println(actionOption, v.ID)
		if actionOption != nil {
			for _, option := range actionOption {
				newActionOption := model.GameActionOption{
					ActionId:   newAction.ID,
					OptionId:   option.OptionId,
					OptionName: option.OptionName,
					OptionType: option.OptionType,
					Status:     option.Status,
					CreatedAt:  now,
					UpdatedAt:  now,
				}

				global.App.DB.Table("game_action_option").Create(&newActionOption)
			}
		}
	}

	response.Success(c, gin.H{})
}
