package logic

import (
	"errors"
	"fusenapi/constants"
	"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/inventory/internal/svc"
	"fusenapi/server/inventory/internal/types"

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

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

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

func (l *SupplementLogic) Supplement(req *types.SupplementReq, userinfo *auth.UserInfo) (resp *basic.Response) {
	if userinfo.GetIdType() != auth.IDTYPE_User {
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "please login first")
	}
	if req.Id <= 0 {
		return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "param id must greater than 0")
	}
	if req.Num <= 0 {
		return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "param num must greater than 0")
	}
	//获取云仓数据
	stockInfo, err := l.svcCtx.AllModels.FsUserStock.FindOne(l.ctx, req.Id, userinfo.UserId, true)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "your stock info is not exists")
		}
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get stock info")
	}
	//获取订单详细模板数据
	orderDetailTemplateInfo, err := l.svcCtx.AllModels.FsOrderDetailTemplate.FindOneBySn(l.ctx, *stockInfo.OrderDetailTemplateSn)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "order detail template info is not exists")
		}
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get order detail template info")
	}
	//获取订单详细数据
	orderDetailInfo, err := l.svcCtx.AllModels.FsOrderDetail.FindOneByOrderDetailTemplateId(l.ctx, orderDetailTemplateInfo.Id)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "order detail info is not exists")
		}
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get order detail info")
	}
	//产品价格
	productPriceByParamsReq := gmodel.FindOneProductPriceByParamsReq{
		ProductId: orderDetailTemplateInfo.ProductId,
	}
	productPriceInfo, err := l.svcCtx.AllModels.FsProductPrice.FindOneProductPriceByParams(l.ctx, productPriceByParamsReq)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "product price info is not exists")
		}
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product price info")
	}
	//获取阶梯价格和阶梯数量
	stepNum, err := format.StrSlicToIntSlice(strings.Split(*productPriceInfo.StepNum, ","))
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "invalid step num format: "+*productPriceInfo.StepNum)
	}
	stepPrice, err := format.StrSlicToIntSlice(strings.Split(*productPriceInfo.StepPrice, ","))
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "invalid step price format: "+*productPriceInfo.StepPrice)
	}
	//附件价格信息
	optionalPrice := int64(0)
	if *orderDetailInfo.OptionPrice > 0 {
		optionalPrice = *orderDetailInfo.OptionPrice
	}
	//获取总价
	minByNum := math.Ceil(float64(req.Num) / float64(*productPriceInfo.EachBoxNum))
	amount := step_price.GetCentStepPrice(int(minByNum), stepNum, stepPrice) + optionalPrice
	totalAmount := amount * req.Num
	newOrderSn := id_generator.GenSnNum()
	now := time.Now().Unix()
	deliveryMethod := int64(constants.DELIVERY_METHOD_CLOUD)
	isSup := int64(1)
	//生成雪花id
	newOrderDetailTemplateSn, err := id_generator.GenSnowFlakeId()
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "gen order detail template sn err")
	}
	newOrderDetailSn, err := id_generator.GenSnowFlakeId()
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "gen order detail  sn err")
	}
	//事务处理数据
	err = l.svcCtx.MysqlConn.Transaction(func(tx *gorm.DB) error {
		orderModel := gmodel.NewFsOrderModel(tx)
		orderDetailModel := gmodel.NewFsOrderDetailModel(tx)
		orderDetailTemplateModel := gmodel.NewFsOrderDetailTemplateModel(tx)
		//订单创建数据
		orderAddData := gmodel.FsOrder{
			Sn:             &newOrderSn,
			UserId:         &userinfo.UserId,
			TotalAmount:    &totalAmount,
			Ctime:          &now,
			Utime:          &now,
			DeliveryMethod: &deliveryMethod,
			IsSup:          &isSup,
		}
		if err = orderModel.Create(l.ctx, &orderAddData); err != nil {
			return err
		}
		//添加订单详情模板数据
		orderDetailTemplateAddData := gmodel.FsOrderDetailTemplate{
			Sn:            &newOrderDetailTemplateSn,
			ProductId:     orderDetailTemplateInfo.ProductId,
			ModelId:       orderDetailTemplateInfo.ModelId,
			TemplateId:    orderDetailTemplateInfo.TemplateId,
			MaterialId:    orderDetailTemplateInfo.MaterialId,
			SizeId:        orderDetailTemplateInfo.SizeId,
			EachBoxNum:    orderDetailTemplateInfo.EachBoxNum,
			EachBoxWeight: orderDetailTemplateInfo.EachBoxWeight,
			DesignId:      orderDetailTemplateInfo.DesignId,
			Ctime:         &now,
		}
		if err = orderDetailTemplateModel.Create(l.ctx, &orderDetailTemplateAddData); err != nil {
			return err
		}
		//添加订单详细数据
		factoryId := int64(1)
		isCloud := int64(1)
		orderDetailAddData := gmodel.FsOrderDetail{
			Sn:                    &newOrderDetailSn,
			OrderId:               &orderAddData.Id,
			UserId:                &userinfo.UserId,
			FactoryId:             &factoryId,
			OrderDetailTemplateId: &orderDetailTemplateAddData.Id,
			ProductId:             orderDetailTemplateInfo.ProductId,
			BuyNum:                &req.Num,
			Amount:                &amount,
			Cover:                 orderDetailInfo.Cover,
			Ctime:                 &now,
			OptionalId:            orderDetailInfo.OptionalId,
			OptionalTitle:         orderDetailInfo.OptionalTitle,
			OptionPrice:           orderDetailInfo.OptionPrice,
			IsCloud:               &isCloud,
		}
		return orderDetailModel.Create(l.ctx, &orderDetailAddData)
	})
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to supplement your stock")
	}
	return resp.SetStatusWithMessage(basic.CodeOK, "success", types.SupplementRsp{
		Sn: newOrderSn,
	})
}