package logic

import (
	"errors"
	"fmt"
	"fusenapi/model/gmodel"
	"fusenapi/utils/auth"
	"fusenapi/utils/basic"
	"fusenapi/utils/format"
	"fusenapi/utils/id_generator"
	"fusenapi/utils/step_price"
	"gorm.io/gorm"
	"math"
	"strings"
	"time"

	"context"

	"fusenapi/server/shopping-cart-confirmation/internal/svc"
	"fusenapi/server/shopping-cart-confirmation/internal/types"

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

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

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

func (l *CreateOrderLogic) CreateOrder(req *types.CreateOrderReq, userinfo *auth.UserInfo) (resp *basic.Response) {
	if userinfo.GetIdType() != auth.IDTYPE_User {
		return resp.SetStatusWithMessage(basic.CodeUnAuth, "please login first")
	}
	if len(req.Form) == 0 {
		return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "err param form:can`t be empty")
	}
	cartIds := make([]int64, 0, len(req.Form))
	mapForm := make(map[int64]int)
	for k, v := range req.Form {
		cartIds = append(cartIds, v.Id)
		mapForm[v.Id] = k
	}
	//获取购物车列表
	cartList, err := l.svcCtx.AllModels.FsCart.GetUserCartsByIds(l.ctx, userinfo.UserId, cartIds)
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get cart list")
	}
	if len(cartList) != len(req.Form) {
		return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "sorry,may be some one not belong to you")
	}
	priceIds := make([]int64, 0, len(cartList))
	optionalIds := make([]int64, 0, len(cartList))
	for _, v := range cartList {
		priceIds = append(priceIds, *v.PriceId)
		optionalIds = append(optionalIds, *v.OptionalId)
	}
	//获取价格
	priceList, err := l.svcCtx.AllModels.FsProductPrice.GetAllByIdsWithoutStatus(l.ctx, priceIds)
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product price list")
	}
	mapPrice := make(map[int64]int)
	for k, v := range priceList {
		mapPrice[v.Id] = k
	}
	//获取附加项
	model3dList, err := l.svcCtx.AllModels.FsProductModel3d.GetAllByIdsWithoutStatus(l.ctx, optionalIds)
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get 3d model list")
	}
	mapModel3d := make(map[int64]int)
	for k, v := range model3dList {
		mapModel3d[v.Id] = k
	}
	var (
		now   = time.Now().Unix()
		total int64 //总价
	)
	orderSn := id_generator.GenSnNum()
	//开启事务
	err = l.svcCtx.MysqlConn.Transaction(func(tx *gorm.DB) error {
		orderDetailTemplateModel := gmodel.NewFsOrderDetailTemplateModel(tx)
		orderDetailModel := gmodel.NewFsOrderDetailModel(tx)
		orderModel := gmodel.NewFsOrderModel(tx)
		//订单数据
		deliveryMethod := int64(1)
		orderCreateData := gmodel.FsOrder{
			Sn:             &orderSn,
			UserId:         &userinfo.UserId,
			Ctime:          &now,
			Utime:          &now,
			DeliveryMethod: &deliveryMethod,
		}
		if err = orderModel.Create(l.ctx, &orderCreateData); err != nil {
			return err
		}
		for _, cart := range cartList {
			priceIndex, ok := mapPrice[*cart.PriceId]
			if !ok {
				return errors.New(fmt.Sprintf("price info is not exists,id = %d", *cart.PriceId))
			}
			//订单详情模板数据
			orderDetailTemplateSn, err := id_generator.GenSnowFlakeId()
			if err != nil {
				return err
			}
			orderDetailTemplateCreateData := gmodel.FsOrderDetailTemplate{
				Sn:            &orderDetailTemplateSn,
				ProductId:     cart.ProductId,
				ModelId:       cart.OptionalId,
				TemplateId:    cart.TemplateId,
				MaterialId:    cart.MaterialId,
				SizeId:        cart.SizeId,
				EachBoxNum:    priceList[priceIndex].EachBoxNum,
				EachBoxWeight: priceList[priceIndex].EachBoxWeight,
				DesignId:      cart.DesignId,
				Ctime:         &now,
			}
			if err = orderDetailTemplateModel.Create(l.ctx, &orderDetailTemplateCreateData); err != nil {
				return err
			}
			//获取阶梯价格和数量
			stepNumSlice, err := format.StrSlicToIntSlice(strings.Split(*priceList[priceIndex].StepNum, ","))
			if err != nil {
				return err
			}
			stepPriceSlice, err := format.StrSlicToIntSlice(strings.Split(*priceList[priceIndex].StepPrice, ","))
			if err != nil {
				return err
			}
			formIndex, _ := mapForm[cart.Id] //一定会有不用判断
			//订单详情数据
			orderDetailSn, err := id_generator.GenSnowFlakeId()
			if err != nil {
				return err
			}
			optionalPrice := int64(0)
			optionalTitle := ""
			if model3dIndex, ok := mapModel3d[*cart.OptionalId]; ok {
				optionalPrice = *model3dList[model3dIndex].Price
				optionalTitle = *model3dList[model3dIndex].Title
			}
			fn := int(math.Ceil(float64(req.Form[formIndex].Num) / float64(*priceList[priceIndex].EachBoxNum)))
			amount := step_price.GetCentStepPrice(fn, stepNumSlice, stepPriceSlice)
			orderDetailCreateData := gmodel.FsOrderDetail{
				OrderId:               &orderCreateData.Id,
				Sn:                    &orderDetailSn,
				UserId:                &userinfo.UserId,
				OrderDetailTemplateId: &orderDetailTemplateCreateData.Id,
				ProductId:             cart.ProductId,
				BuyNum:                &req.Form[formIndex].Num, //以提交数量为准
				Amount:                &amount,
				Cover:                 cart.Cover,
				Ctime:                 &now,
				OptionalId:            cart.OptionalId,
				OptionalTitle:         &optionalTitle,
				OptionPrice:           &optionalPrice,
				CartId:                &cart.Id,
			}
			if err = orderDetailModel.Create(l.ctx, &orderDetailCreateData); err != nil {
				return err
			}
			total += amount * (*orderDetailCreateData.BuyNum)
		}
		//更新订单总价
		return orderModel.Update(l.ctx, &gmodel.FsOrder{
			Id:          orderCreateData.Id,
			TotalAmount: &total,
		})
	})
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to create order")
	}
	return resp.SetStatusWithMessage(basic.CodeOK, "success", types.CreateOrderRsp{
		Sn: orderSn,
	})
}