package admin

import (
	"bytes"
	"fmt"
	"net/http"
	"time"

	"bindbox-game/internal/code"
	"bindbox-game/internal/pkg/core"
	"bindbox-game/internal/pkg/validation"

	"github.com/tealeg/xlsx"
)

type exportOrdersRequest struct {
	Status     *int32 `form:"status"`
	SourceType *int32 `form:"source_type"`
	StartDate  string `form:"start_date"`
	EndDate    string `form:"end_date"`
}

func (h *handler) ExportPayOrders() core.HandlerFunc {
	return func(ctx core.Context) {
		req := new(exportOrdersRequest)
		if err := ctx.ShouldBindForm(req); err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
			return
		}
		q := h.readDB.Orders.WithContext(ctx.RequestContext()).ReadDB()
		if req.Status != nil {
			q = q.Where(h.readDB.Orders.Status.Eq(*req.Status))
		}
		if req.SourceType != nil {
			q = q.Where(h.readDB.Orders.SourceType.Eq(*req.SourceType))
		}
		if req.StartDate != "" {
			if t, err := time.Parse("2006-01-02", req.StartDate); err == nil {
				q = q.Where(h.readDB.Orders.CreatedAt.Gte(t))
			}
		}
		if req.EndDate != "" {
			if t, err := time.Parse("2006-01-02", req.EndDate); err == nil {
				t = t.Add(24 * time.Hour).Add(-time.Second)
				q = q.Where(h.readDB.Orders.CreatedAt.Lte(t))
			}
		}
		rows, err := q.Order(h.readDB.Orders.ID.Desc()).Limit(5000).Find()
		if err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, 23001, err.Error()))
			return
		}
		var pointsRate int64 = 1
		if cfgRate, _ := h.readDB.SystemConfigs.WithContext(ctx.RequestContext()).Where(h.readDB.SystemConfigs.ConfigKey.Eq("points_exchange_per_cent")).First(); cfgRate != nil {
			var r int64
			_, _ = fmt.Sscanf(cfgRate.ConfigValue, "%d", &r)
			if r > 0 {
				pointsRate = r
			}
		}
		file := xlsx.NewFile()
		sheet, _ := file.AddSheet("orders")
		header := []string{"订单号", "用户ID", "来源", "状态", "总金额", "折扣", "积分抵扣(分)", "积分抵扣(积分)", "优惠券抵扣(分)", "实付", "支付时间", "创建时间"}
		row := sheet.AddRow()
		for _, hname := range header {
			cell := row.AddCell()
			cell.Value = hname
		}
		for _, o := range rows {
			leds, _ := h.readDB.UserPointsLedger.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.UserPointsLedger.RefTable.Eq("orders"), h.readDB.UserPointsLedger.RefID.Eq(o.OrderNo)).Find()
			var consumePointsSum int64
			for _, lg := range leds {
				if lg.Points < 0 {
					consumePointsSum += -lg.Points
				}
			}
			pa := o.PointsAmount
			if pa == 0 && consumePointsSum > 0 {
				pa = consumePointsSum / pointsRate
			}
			pu := int64(0)
			if consumePointsSum > 0 {
				pu = consumePointsSum
			} else if pa > 0 {
				pu = pa * pointsRate
			}
			ocs, _ := h.readDB.OrderCoupons.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.OrderCoupons.OrderID.Eq(o.ID)).Find()
			var couponApplied int64
			for _, oc := range ocs {
				couponApplied += oc.AppliedAmount
			}
			r := sheet.AddRow()
			r.AddCell().Value = o.OrderNo
			r.AddCell().SetInt64(o.UserID)
			r.AddCell().SetInt(int(o.SourceType))
			r.AddCell().SetInt(int(o.Status))
			r.AddCell().SetInt64(o.TotalAmount)
			r.AddCell().SetInt64(o.DiscountAmount)
			r.AddCell().SetInt64(pa)
			r.AddCell().SetInt64(pu)
			r.AddCell().SetInt64(couponApplied)
			r.AddCell().SetInt64(o.ActualAmount)
			if !o.PaidAt.IsZero() {
				r.AddCell().Value = o.PaidAt.Format("2006-01-02 15:04:05")
			} else {
				r.AddCell().Value = ""
			}
			r.AddCell().Value = o.CreatedAt.Format("2006-01-02 15:04:05")
		}
		var buf bytes.Buffer
		if err := file.Write(&buf); err != nil {
			ctx.AbortWithError(core.Error(http.StatusBadRequest, 23002, err.Error()))
			return
		}
		ctx.ExcelData("orders.xlsx", buf.Bytes())
	}
}
