package dashboard

import (
	"context"
	"fmt"
	"github.com/suyuan32/simple-admin-common/msg/errormsg"
	"math"
	"strconv"
	"time"
	"wechat-api/ent/custom_types"
	"wechat-api/ent/label"
	"wechat-api/ent/predicate"
	"wechat-api/ent/usagedetail"
	"wechat-api/ent/usagestatisticday"
	"wechat-api/ent/usagestatistichour"
	"wechat-api/internal/svc"
	"wechat-api/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type GetChartsLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetChartsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetChartsLogic {
	return &GetChartsLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx}
}

type SumUint struct {
	Addtime uint64 `json:"addtime"`
	Value   uint64 `json:"value"`
}

type SumInt struct {
	Addtime uint64 `json:"addtime"`
	Value   int64  `json:"value"`
}

func (l *GetChartsLogic) GetCharts(req *types.ChartsReq) (resp *types.ChartsResp, err error) {
	// 获取组织id
	var organizationId uint64 = 0
	isAdmin := l.ctx.Value("isAdmin").(bool)
	if isAdmin {
		if req.OrganizationId != nil && *req.OrganizationId != 0 {
			organizationId = *req.OrganizationId
		}
	} else {
		organizationId = l.ctx.Value("organizationId").(uint64)
	}
	// 解析起始和截止时间
	layouts := []string{
		"2006-01",    // 对应 "2024-01"
		"2006-01-02", // 对应 "2024-01-01"
	}

	var layoutsType int

	var startTime time.Time
	for i, layout := range layouts {
		startTime, err = time.Parse(layout, *req.StartDate)
		layoutsType = i
		if err == nil {
			break
		}
	}

	if err != nil {
		fmt.Println("解析开始时间失败:", err)
		return
	}

	var endTime time.Time
	for _, layout := range layouts {
		endTime, err = time.Parse(layout, *req.EndDate)
		if err == nil {
			break
		}
	}
	if err != nil {
		fmt.Println("解析结束时间失败:", err)
		return
	}

	// 判断截止日期是否包含当前日
	var isCurrentDay bool
	now := time.Now()

	if layoutsType == 0 {
		isCurrentDay = endTime.Year() == now.Year() && endTime.Month() == now.Month()
	} else {
		isCurrentDay = endTime.Year() == now.Year() && endTime.Month() == now.Month() && endTime.Day() == now.Day()
	}

	aiResponseTip := "AI角色 + SOP 执行次数"
	sopRunTip := "SOP 节点或阶段的触发次数"
	totalFriendTip := "截止至各统计时点的好友数量"
	totalGroupTip := "截止至各统计时点的群数量"
	activeUserTip := "统计周期内回复sop 或触发了AI角色的微信用户"
	newUserTip := "统计周期内好友的增减数量"

	// 定义变量
	aiResponse := types.ChartsUint{}
	aiResponse.Tip = &aiResponseTip
	sopRun := types.ChartsUint{}
	sopRun.Tip = &sopRunTip
	totalFriend := types.ChartsUint{}
	totalFriend.Tip = &totalFriendTip
	totalGroup := types.ChartsUint{}
	totalGroup.Tip = &totalGroupTip
	accountBalance := types.ChartsUint{}
	accountBalance.LabelText = "积分"
	consumeToken := types.ChartsUint{}
	activeUser := types.ChartsUint{}
	activeUser.Tip = &activeUserTip
	newUser := types.ChartsInt{}
	newUser.Tip = &newUserTip
	var labelDists []custom_types.LabelDist
	if layoutsType == 1 && *req.StartDate == *req.EndDate {
		startAddTimeString := startTime.Format("2006010200")
		startAddTime, err := strconv.ParseUint(startAddTimeString, 10, 64)
		if err != nil {
			fmt.Println("转换开始时间失败:", err)
			return nil, err
		}

		nextDayMidnight := time.Date(startTime.Year(), startTime.Month(), startTime.Day()+1, 0, 0, 0, 0, startTime.Location())
		nextDayMidnightString := nextDayMidnight.Format("2006010200")
		nextDayAddTime, err := strconv.ParseUint(nextDayMidnightString, 10, 64)
		if err != nil {
			fmt.Println("转换次日0点时间失败:", err)
			return nil, err
		}

		var predicates []predicate.UsageStatisticHour
		if req.Wxid != nil {
			if organizationId != 0 {
				predicates = append(predicates, usagestatistichour.OrganizationID(organizationId))
			}
			predicates = append(predicates, usagestatistichour.BotID(*req.Wxid))
		} else {
			predicates = append(predicates, usagestatistichour.OrganizationID(organizationId))
			predicates = append(predicates, usagestatistichour.BotID(""))
		}
		predicates = append(predicates, usagestatistichour.AddtimeGTE(startAddTime))
		predicates = append(predicates, usagestatistichour.AddtimeLT(nextDayAddTime))
		usageStatisticHour, err := l.svcCtx.DB.UsageStatisticHour.Query().Where(predicates...).All(l.ctx)
		if err != nil {
			return nil, err
		}
		for _, hourData := range usageStatisticHour {
			addtimeLastTwoDigits := hourData.Addtime % 100
			aiResponse.Count += hourData.AiResponse
			aiResponse.Val = append(aiResponse.Val, hourData.AiResponse)
			aiResponse.Label = append(aiResponse.Label, fmt.Sprintf("%02d-%02d点", addtimeLastTwoDigits, addtimeLastTwoDigits+1))
			aiResponse.LabelText = "次"

			sopRun.Count += hourData.SopRun
			sopRun.Val = append(sopRun.Val, hourData.SopRun)
			sopRun.Label = append(sopRun.Label, fmt.Sprintf("%02d-%02d点", addtimeLastTwoDigits, addtimeLastTwoDigits+1))
			sopRun.LabelText = "次"

			totalFriend.Count = hourData.TotalFriend
			totalFriend.Val = append(totalFriend.Val, hourData.TotalFriend)
			totalFriend.Label = append(totalFriend.Label, fmt.Sprintf("%02d点", addtimeLastTwoDigits+1))
			totalFriend.LabelText = "个"

			totalGroup.Count = hourData.TotalGroup
			totalGroup.Val = append(totalGroup.Val, hourData.TotalGroup)
			totalGroup.Label = append(totalGroup.Label, fmt.Sprintf("%02d点", addtimeLastTwoDigits+1))
			totalGroup.LabelText = "个"

			consumeToken.Count += hourData.ConsumeToken
			consumeToken.Val = append(consumeToken.Val, hourData.ConsumeToken)
			consumeToken.Label = append(consumeToken.Label, fmt.Sprintf("%02d-%02d点", addtimeLastTwoDigits, addtimeLastTwoDigits+1))
			consumeToken.LabelText = "token"

			//activeUser.Count = hourData.ActiveUser
			activeUser.Val = append(activeUser.Val, hourData.ActiveUser)
			activeUser.Label = append(activeUser.Label, fmt.Sprintf("%02d-%02d点", addtimeLastTwoDigits, addtimeLastTwoDigits+1))
			activeUser.LabelText = "个"

			newUser.Count += hourData.NewUser
			newUser.Val = append(newUser.Val, hourData.NewUser)
			newUser.Label = append(newUser.Label, fmt.Sprintf("%02d-%02d点", addtimeLastTwoDigits, addtimeLastTwoDigits+1))
			newUser.LabelText = "个"
		}

		// 活跃好友：usage_detail 表 type = 1
		var usageDetailPredicates []predicate.UsageDetail
		if organizationId != 0 {
			usageDetailPredicates = append(usageDetailPredicates, usagedetail.OrganizationID(organizationId))
		}
		if req.Wxid != nil {
			usageDetailPredicates = append(usageDetailPredicates, usagedetail.BotID(*req.Wxid))
		}
		usageDetailPredicates = append(usageDetailPredicates, usagedetail.Type(1))
		usageDetailPredicates = append(usageDetailPredicates, usagedetail.CreatedAtGTE(startTime))
		usageDetailPredicates = append(usageDetailPredicates, usagedetail.CreatedAtLT(nextDayMidnight))
		activeUsers, _ := l.svcCtx.DB.UsageDetail.Query().Where(usageDetailPredicates...).GroupBy(usagedetail.FieldReceiverID).Strings(l.ctx)
		activeUser.Count = uint64(len(activeUsers))

		hourLen := len(usageStatisticHour)
		if hourLen > 0 {
			if usageStatisticHour[0].TotalFriend > 0 {
				totalFriendRate := float32((float64(usageStatisticHour[hourLen-1].TotalFriend) - float64(usageStatisticHour[0].TotalFriend)) / float64(usageStatisticHour[0].TotalFriend))
				totalFriendRateRound := float32(math.Round(float64(totalFriendRate) * 100))
				totalFriend.Rate = &totalFriendRateRound
				//totalFriend.Rate = &totalFriendRate
			}
			if usageStatisticHour[0].TotalGroup > 0 {
				totalGroupRate := float32((float64(usageStatisticHour[hourLen-1].TotalGroup) - float64(usageStatisticHour[0].TotalGroup)) / float64(usageStatisticHour[0].TotalGroup))
				totalGroupRateRound := float32(math.Round(float64(totalGroupRate) * 100))
				totalGroup.Rate = &totalGroupRateRound
			}
			//if usageStatisticHour[0].ActiveUser > 0 {
			//	activeUserRate := float32((float64(usageStatisticHour[hourLen-1].ActiveUser) - float64(usageStatisticHour[0].ActiveUser)) / float64(usageStatisticHour[0].ActiveUser))
			//	activeUserRateRound := float32(math.Round(float64(activeUserRate)*100))
			//	activeUser.Rate = &activeUserRateRound
			//}
			if usageStatisticHour[0].NewUser > 0 {
				newUserRate := float32((float64(usageStatisticHour[hourLen-1].NewUser) - float64(usageStatisticHour[0].NewUser)) / float64(usageStatisticHour[0].NewUser))
				newUserRateRound := float32(math.Round(float64(newUserRate) * 100))
				newUser.Rate = &newUserRateRound
			}
			labelDists = usageStatisticHour[hourLen-1].LabelDist
		}
	} else {
		// 从天表统计数据
		startAddTimeString := startTime.Format("20060102")
		startAddTime, err := strconv.ParseUint(startAddTimeString, 10, 64)
		if err != nil {
			fmt.Println("转换开始时间失败:", err)
			return nil, err
		}
		endAddTimeString := endTime.Format("20060102")
		endAddTime, err := strconv.ParseUint(endAddTimeString, 10, 64)

		nextDayMidnight := time.Date(endTime.Year(), endTime.Month(), endTime.Day()+1, 0, 0, 0, 0, endTime.Location())
		if err != nil {
			fmt.Println("转换截止时间失败:", err)
			return nil, err
		}

		var predicatesDay []predicate.UsageStatisticDay
		if req.Wxid != nil {
			if organizationId != 0 {
				predicatesDay = append(predicatesDay, usagestatisticday.OrganizationID(organizationId))
			}
			predicatesDay = append(predicatesDay, usagestatisticday.BotID(*req.Wxid))
		} else {
			predicatesDay = append(predicatesDay, usagestatisticday.OrganizationID(organizationId))
			predicatesDay = append(predicatesDay, usagestatisticday.BotID(""))
		}
		predicatesDay = append(predicatesDay, usagestatisticday.AddtimeGTE(startAddTime))
		predicatesDay = append(predicatesDay, usagestatisticday.AddtimeLTE(endAddTime))
		usageStatisticDay, err := l.svcCtx.DB.UsageStatisticDay.Query().Where(predicatesDay...).All(l.ctx)
		if err != nil {
			return nil, err
		}
		for _, dayData := range usageStatisticDay {
			aiResponse.Count = aiResponse.Count + dayData.AiResponse
			aiResponse.Val = append(aiResponse.Val, dayData.AiResponse)
			aiResponse.Label = append(aiResponse.Label, fmt.Sprintf("%d", dayData.Addtime))
			aiResponse.LabelText = "次"

			sopRun.Count += dayData.SopRun
			sopRun.Val = append(sopRun.Val, dayData.SopRun)
			sopRun.Label = append(sopRun.Label, fmt.Sprintf("%d", dayData.Addtime))
			sopRun.LabelText = "次"

			totalFriend.Count = dayData.TotalFriend
			totalFriend.Val = append(totalFriend.Val, dayData.TotalFriend)
			totalFriend.Label = append(totalFriend.Label, fmt.Sprintf("%d", dayData.Addtime))
			totalFriend.LabelText = "个"

			totalGroup.Count = dayData.TotalGroup
			totalGroup.Val = append(totalGroup.Val, dayData.TotalGroup)
			totalGroup.Label = append(totalGroup.Label, fmt.Sprintf("%d", dayData.Addtime))
			totalGroup.LabelText = "个"

			consumeToken.Count += dayData.ConsumeToken
			consumeToken.Val = append(consumeToken.Val, dayData.ConsumeToken)
			consumeToken.Label = append(consumeToken.Label, fmt.Sprintf("%d", dayData.Addtime))
			consumeToken.LabelText = "token"

			//activeUser.Count = dayData.ActiveUser
			activeUser.Val = append(activeUser.Val, dayData.ActiveUser)
			activeUser.Label = append(activeUser.Label, fmt.Sprintf("%d", dayData.Addtime))
			activeUser.LabelText = "个"

			newUser.Count += dayData.NewUser
			newUser.Val = append(newUser.Val, dayData.NewUser)
			newUser.Label = append(newUser.Label, fmt.Sprintf("%d", dayData.Addtime))
			newUser.LabelText = "个"
		}
		dayLen := len(usageStatisticDay)
		if dayLen > 0 {
			if usageStatisticDay[0].TotalFriend > 0 {
				totalFriendRate := float32((float64(usageStatisticDay[dayLen-1].TotalFriend) - float64(usageStatisticDay[0].TotalFriend)) / float64(usageStatisticDay[0].TotalFriend))
				totalFriendRateRound := float32(math.Round(float64(totalFriendRate) * 100))
				totalFriend.Rate = &totalFriendRateRound
			}
			if usageStatisticDay[0].TotalGroup > 0 {
				totalGroupRate := float32((float64(usageStatisticDay[dayLen-1].TotalGroup) - float64(usageStatisticDay[0].TotalGroup)) / float64(usageStatisticDay[0].TotalGroup))
				totalGroupRateRound := float32(math.Round(float64(totalGroupRate) * 100))
				totalGroup.Rate = &totalGroupRateRound
			}
			//if usageStatisticDay[0].ActiveUser > 0 {
			//	activeUserRate := float32((float64(usageStatisticDay[dayLen-1].ActiveUser) - float64(usageStatisticDay[0].ActiveUser)) / float64(usageStatisticDay[0].ActiveUser))
			//	activeUserRateRound := float32(math.Round(float64(activeUserRate)*100))
			//	activeUser.Rate = &activeUserRateRound
			//}
			if usageStatisticDay[0].NewUser > 0 {
				newUserRate := float32((float64(usageStatisticDay[dayLen-1].NewUser) - float64(usageStatisticDay[0].NewUser)) / float64(usageStatisticDay[0].NewUser))
				newUserRateRound := float32(math.Round(float64(newUserRate) * 100))
				newUser.Rate = &newUserRateRound
			}
			labelDists = usageStatisticDay[dayLen-1].LabelDist
		}

		if isCurrentDay {
			// 从小时表统计当天数据
			startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC)
			startOfDayAddTimeString := startOfDay.Format("2006010200")
			startOfDayAddTime, err := strconv.ParseUint(startOfDayAddTimeString, 10, 64)
			if err != nil {
				fmt.Println("转换开始时间失败:", err)
				return nil, err
			}

			var predicates []predicate.UsageStatisticHour
			if req.Wxid != nil {
				if organizationId != 0 {
					predicates = append(predicates, usagestatistichour.OrganizationID(organizationId))
				}
				predicates = append(predicates, usagestatistichour.BotID(*req.Wxid))
			} else {
				predicates = append(predicates, usagestatistichour.OrganizationID(organizationId))
				predicates = append(predicates, usagestatistichour.BotID(""))
			}
			predicates = append(predicates, usagestatistichour.AddtimeGTE(startOfDayAddTime))
			usageStatisticHour, err := l.svcCtx.DB.UsageStatisticHour.Query().Where(predicates...).All(l.ctx)
			if err != nil {
				return nil, err
			}
			hourLen := len(usageStatisticHour)
			if hourLen > 0 {
				var aiResponseOfDay uint64
				var sopRunOfDay uint64
				var totalFriendOfDay uint64
				var totalGroupOfDay uint64
				var consumeTokenOfDay uint64
				var activeUserOfDay uint64
				var newUserOfDay int64

				for _, hourData := range usageStatisticHour {
					aiResponseOfDay += hourData.AiResponse
					sopRunOfDay += hourData.SopRun
					consumeTokenOfDay += hourData.ConsumeToken
				}
				totalFriendOfDay = usageStatisticHour[hourLen-1].TotalFriend
				totalGroupOfDay = usageStatisticHour[hourLen-1].TotalGroup
				activeUserOfDay = usageStatisticHour[hourLen-1].ActiveUser
				newUserOfDay = usageStatisticHour[hourLen-1].NewUser

				aiResponse.Count = aiResponse.Count + aiResponseOfDay
				aiResponse.Val = append(aiResponse.Val, aiResponseOfDay)
				aiResponse.Label = append(aiResponse.Label, "今日")
				aiResponse.LabelText = "次"

				sopRun.Count = sopRun.Count + sopRunOfDay
				sopRun.Val = append(sopRun.Val, sopRunOfDay)
				sopRun.Label = append(sopRun.Label, "今日")
				sopRun.LabelText = "次"

				totalFriend.Count = totalFriendOfDay
				totalFriend.Val = append(totalFriend.Val, totalFriendOfDay)
				totalFriend.Label = append(totalFriend.Label, "今日")
				tfLen := len(totalFriend.Val)
				if tfLen > 0 && totalFriend.Val[0] > 0 {
					totalFriendRate := float32((float64(totalFriend.Val[tfLen-1]) - float64(totalFriend.Val[0])) / float64(totalFriend.Val[0]))
					totalFriendRateRound := float32(math.Round(float64(totalFriendRate) * 100))
					totalFriend.Rate = &totalFriendRateRound
				}
				totalFriend.LabelText = "个"

				totalGroup.Count = totalGroupOfDay
				totalGroup.Val = append(totalGroup.Val, totalGroupOfDay)
				totalGroup.Label = append(totalGroup.Label, "今日")
				tgLen := len(totalGroup.Val)
				if tgLen > 0 && totalGroup.Val[0] > 0 {
					totalGroupRate := float32((float64(totalGroup.Val[tgLen-1]) - float64(totalGroup.Val[0])) / float64(totalGroup.Val[0]))
					totalGroupRateRound := float32(math.Round(float64(totalGroupRate) * 100))
					totalGroup.Rate = &totalGroupRateRound
				}
				totalGroup.LabelText = "个"

				consumeToken.Count = consumeToken.Count + consumeTokenOfDay
				consumeToken.Val = append(consumeToken.Val, consumeTokenOfDay)
				consumeToken.Label = append(consumeToken.Label, "今日")
				consumeToken.LabelText = "token"

				//activeUser.Count = activeUserOfDay
				activeUser.Val = append(activeUser.Val, activeUserOfDay)
				activeUser.Label = append(activeUser.Label, "今日")
				//auLen := len(activeUser.Val)
				//if auLen > 0 && activeUser.Val[0] > 0 {
				//	activeUserRate := float32((float64(activeUser.Val[auLen-1]) - float64(activeUser.Val[0])) / float64(activeUser.Val[0]))
				//	activeUserRateRound := float32(math.Round(float64(activeUserRate)*100))
				//	activeUser.Rate = &activeUserRateRound
				//}
				activeUser.LabelText = "个"

				newUser.Count = newUserOfDay
				newUser.Val = append(newUser.Val, newUserOfDay)
				newUser.Label = append(newUser.Label, "今日")
				nuLen := len(newUser.Val)
				if nuLen > 0 && newUser.Val[0] > 0 {
					newUserRate := float32((float64(newUser.Val[nuLen-1]) - float64(newUser.Val[0])) / float64(newUser.Val[0]))
					newUserRateRound := float32(math.Round(float64(newUserRate) * 100))
					newUser.Rate = &newUserRateRound
				}
				newUser.LabelText = "个"

				labelDists = usageStatisticHour[hourLen-1].LabelDist
			}
		}

		// 活跃好友：usage_detail 表 type = 1
		var usageDetailPredicates []predicate.UsageDetail
		if organizationId != 0 {
			usageDetailPredicates = append(usageDetailPredicates, usagedetail.OrganizationID(organizationId))
		}
		if req.Wxid != nil {
			usageDetailPredicates = append(usageDetailPredicates, usagedetail.BotID(*req.Wxid))
		}
		usageDetailPredicates = append(usageDetailPredicates, usagedetail.Type(1))
		usageDetailPredicates = append(usageDetailPredicates, usagedetail.CreatedAtGTE(startTime))
		usageDetailPredicates = append(usageDetailPredicates, usagedetail.CreatedAtLT(nextDayMidnight))
		activeUsers, _ := l.svcCtx.DB.UsageDetail.Query().Where(usageDetailPredicates...).GroupBy(usagedetail.FieldReceiverID).Strings(l.ctx)
		activeUser.Count = uint64(len(activeUsers))
	}

	var labelIds []uint64
	var labelsData []types.LabelsData
	labelSet := make(map[uint64]uint64)
	for _, labelDist := range labelDists {
		if labelDist.Count != 0 {
			labelIds = append(labelIds, labelDist.LabelID)
			labelSet[labelDist.LabelID] = labelDist.Count
		}
	}

	labelInfos, err := l.svcCtx.DB.Label.Query().Where(label.IDIn(labelIds...)).All(l.ctx)
	for _, labelInfo := range labelInfos {
		labelsData = append(labelsData, types.LabelsData{
			Value: labelSet[labelInfo.ID],
			Name:  labelInfo.Name,
		})
	}

	chartsData := types.ChartsData{
		AiResponse:     &aiResponse,
		SopRun:         &sopRun,
		TotalFriend:    &totalFriend,
		TotalGroup:     &totalGroup,
		AccountBalance: &accountBalance,
		ConsumeToken:   &consumeToken,
		ActiveUser:     &activeUser,
		NewUser:        &newUser,
		LabelDist:      labelsData,
	}

	return &types.ChartsResp{BaseDataInfo: types.BaseDataInfo{Msg: errormsg.UpdateSuccess}, Data: &chartsData}, nil
}
