package admin_promotion

import (
	"context"
	"time"

	"hm-server/app/main/api/internal/svc"
	"hm-server/app/main/api/internal/types"
	"hm-server/app/main/model"
	"hm-server/common/ctxdata"
	"hm-server/common/xerr"

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

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

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

func (l *GetPromotionStatsTotalLogic) GetPromotionStatsTotal(req *types.GetPromotionStatsTotalReq) (resp *types.GetPromotionStatsTotalResp, err error) {
	// 获取当前用户ID
	adminUserId, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
	if getUidErr != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取当前用户ID失败, %+v", getUidErr)
	}

	// 获取用户的所有推广链接
	linkBuilder := l.svcCtx.AdminPromotionLinkModel.SelectBuilder()
	linkBuilder = linkBuilder.Where("admin_user_id = ?", adminUserId)
	links, err := l.svcCtx.AdminPromotionLinkModel.FindAll(l.ctx, linkBuilder, "")
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取推广链接列表失败, %+v", err)
	}

	// 如果没有推广链接，返回空统计
	if len(links) == 0 {
		return &types.GetPromotionStatsTotalResp{}, nil
	}

	// 构建链接ID列表
	linkIds := make([]int64, len(links))
	for i, link := range links {
		linkIds[i] = link.Id
	}

	// 获取并计算总统计数据
	var totalClickCount, totalPayCount int64
	var totalPayAmount float64
	err = mr.MapReduceVoid(func(source chan<- interface{}) {
		for _, linkId := range linkIds {
			source <- linkId
		}
	}, func(item interface{}, writer mr.Writer[struct {
		ClickCount int64
		PayCount   int64
		PayAmount  float64
	}], cancel func(error)) {
		linkId := item.(int64)
		stats, err := l.svcCtx.AdminPromotionLinkStatsTotalModel.FindOneByLinkId(l.ctx, linkId)
		if err != nil && !errors.Is(err, model.ErrNotFound) {
			cancel(errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取总统计数据失败, linkId: %d, %+v", linkId, err))
			return
		}
		if stats != nil {
			writer.Write(struct {
				ClickCount int64
				PayCount   int64
				PayAmount  float64
			}{
				ClickCount: stats.ClickCount,
				PayCount:   stats.PayCount,
				PayAmount:  stats.PayAmount,
			})
		}
	}, func(pipe <-chan struct {
		ClickCount int64
		PayCount   int64
		PayAmount  float64
	}, cancel func(error)) {
		for stats := range pipe {
			totalClickCount += stats.ClickCount
			totalPayCount += stats.PayCount
			totalPayAmount += stats.PayAmount
		}
	})
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取总统计数据失败, %+v", err)
	}

	// 获取今日统计数据
	now := time.Now()
	today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
	var todayClickCount, todayPayCount int64
	var todayPayAmount float64

	err = mr.MapReduceVoid(func(source chan<- interface{}) {
		for _, linkId := range linkIds {
			source <- linkId
		}
	}, func(item interface{}, writer mr.Writer[struct {
		ClickCount int64
		PayCount   int64
		PayAmount  float64
	}], cancel func(error)) {
		linkId := item.(int64)
		builder := l.svcCtx.AdminPromotionLinkStatsHistoryModel.SelectBuilder()
		builder = builder.Where("link_id = ? AND DATE(stats_date) = DATE(?)", linkId, today)
		histories, err := l.svcCtx.AdminPromotionLinkStatsHistoryModel.FindAll(l.ctx, builder, "")
		if err != nil {
			cancel(errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取今日统计数据失败, linkId: %d, %+v", linkId, err))
			return
		}

		var clickCount, payCount int64
		var payAmount float64
		for _, history := range histories {
			clickCount += history.ClickCount
			payCount += history.PayCount
			payAmount += history.PayAmount
		}

		writer.Write(struct {
			ClickCount int64
			PayCount   int64
			PayAmount  float64
		}{
			ClickCount: clickCount,
			PayCount:   payCount,
			PayAmount:  payAmount,
		})
	}, func(pipe <-chan struct {
		ClickCount int64
		PayCount   int64
		PayAmount  float64
	}, cancel func(error)) {
		for stats := range pipe {
			todayClickCount += stats.ClickCount
			todayPayCount += stats.PayCount
			todayPayAmount += stats.PayAmount
		}
	})
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取今日统计数据失败, %+v", err)
	}

	return &types.GetPromotionStatsTotalResp{
		TodayClickCount: int64(todayClickCount),
		TodayPayCount:   int64(todayPayCount),
		TodayPayAmount:  todayPayAmount,
		TotalClickCount: int64(totalClickCount),
		TotalPayCount:   int64(totalPayCount),
		TotalPayAmount:  totalPayAmount,
	}, nil
}
