package logic

import (
	"fmt"
	"fusenapi/constants"
	"fusenapi/model/gmodel"
	"fusenapi/utils/auth"
	"fusenapi/utils/basic"
	"fusenapi/utils/format"
	"fusenapi/utils/image"
	"fusenapi/utils/step_price"
	"math"
	"strings"

	"context"

	"fusenapi/server/inventory/internal/svc"
	"fusenapi/server/inventory/internal/types"

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

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

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

func (l *GetCloudListLogic) GetCloudList(req *types.GetCloudListReq, userinfo *auth.UserInfo) (resp *basic.Response) {
	if userinfo.GetIdType() != auth.IDTYPE_User {
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "please login first")
	}
	if req.Page <= 0 {
		req.Page = constants.DEFAULT_PAGE
	}
	if req.PageSize <= 0 || req.PageSize > constants.MAX_PAGE_SIZE {
		req.PageSize = constants.DEFAULT_PAGE_SIZE
	}
	sizeFlag := false
	if req.Size >= 200 {
		sizeFlag = true
		req.Size = int64(image.GetCurrentSize(uint32(req.Size)))
	}
	//获取个人云仓列表
	getStockListStatus := int64(1)
	stockList, total, err := l.svcCtx.AllModels.FsUserStock.GetStockList(l.ctx, gmodel.GetStockListReq{
		UserId: userinfo.UserId,
		Page:   int(req.Page),
		Limit:  int(req.PageSize),
		Status: &getStockListStatus,
	})
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get user stock list")
	}
	if len(stockList) == 0 {
		return resp.SetStatusWithMessage(basic.CodeOK, "success")
	}
	designIds := make([]int64, 0, len(stockList))
	for _, v := range stockList {
		designIds = append(designIds, *v.DesignId)
	}
	//获取设计数据
	productDesignList, err := l.svcCtx.AllModels.FsProductDesign.GetAllByIdsWithoutStatus(l.ctx, designIds)
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product design list")
	}
	//尺寸ids
	sizeIds := make([]int64, 0, len(productDesignList))
	//产品ids
	productIds := make([]int64, 0, len(productDesignList))
	//模板ids
	templateIds := make([]int64, 0, len(productDesignList))
	//配件ids
	optionalIds := make([]int64, 0, len(productDesignList))
	mapProductDesign := make(map[int64]gmodel.FsProductDesign)
	for _, v := range productDesignList {
		sizeIds = append(sizeIds, *v.SizeId)
		productIds = append(productIds, *v.ProductId)
		templateIds = append(templateIds, *v.TemplateId)
		optionalIds = append(optionalIds, *v.OptionalId)
		mapProductDesign[v.Id] = v
	}
	//获取尺寸信息
	sizeList, err := l.svcCtx.AllModels.FsProductSize.GetAllByIdsWithoutStatus(l.ctx, sizeIds, "")
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product size list")
	}
	mapSize := make(map[int64]gmodel.FsProductSize)
	for _, v := range sizeList {
		mapSize[v.Id] = v
	}
	//获取产品信息
	productList, err := l.svcCtx.AllModels.FsProduct.GetProductListByIdsWithoutStatus(l.ctx, productIds, "")
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product list")
	}
	mapProduct := make(map[int64]gmodel.FsProduct)
	for _, v := range productList {
		mapProduct[v.Id] = v
	}
	//获取模板信息
	productTemplateList, err := l.svcCtx.AllModels.FsProductTemplateV2.FindAllByIdsWithoutStatus(l.ctx, templateIds)
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product template list")
	}
	mapTemplate := make(map[int64]gmodel.FsProductTemplateV2)
	for _, v := range productTemplateList {
		mapTemplate[v.Id] = v
	}
	//获取配件列表
	productModel3dList, err := l.svcCtx.AllModels.FsProductModel3d.GetAllByIdsWithoutStatus(l.ctx, optionalIds)
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product 3d model list")
	}
	mapProductModel := make(map[int64]gmodel.FsProductModel3d)
	for _, v := range productModel3dList {
		mapProductModel[v.Id] = v
	}
	//根据产品ids获取产品价格
	priceList, err := l.svcCtx.AllModels.FsProductPrice.GetPriceListByProductIds(l.ctx, productIds)
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product price list")
	}
	//根据产品id,材质,尺寸存储价格
	mapProductMaterialSizePrice := make(map[string][]types.PriceItem)
	for _, v := range priceList {
		if *v.StepNum == "" || *v.StepPrice == "" {
			return resp.SetStatusWithMessage(basic.CodeServiceErr, "price data`s step num or step price is empty")
		}
		stepNum, err := format.StrSlicToIntSlice(strings.Split(*v.StepNum, ","))
		if err != nil {
			logx.Error(err)
			return resp.SetStatusWithMessage(basic.CodeServiceErr, "parse step num err")
		}
		stepPrice, err := format.StrSlicToIntSlice(strings.Split(*v.StepPrice, ","))
		if err != nil {
			logx.Error(err)
			return resp.SetStatusWithMessage(basic.CodeServiceErr, "parse step price err")
		}
		lenStepPrice := len(stepPrice)
		//不确定长度给20
		for *v.MinBuyNum < int64(stepPrice[lenStepPrice-1]+5) {
			mapKey := l.getMapProductMaterialSizePriceKey(*v.ProductId, *v.MaterialId, *v.SizeId)
			mapProductMaterialSizePrice[mapKey] = append(mapProductMaterialSizePrice[mapKey], types.PriceItem{
				Num:      *v.MinBuyNum,
				TotalNum: *v.MinBuyNum * (*v.EachBoxNum),
				Price:    step_price.GetCentStepPrice(int(*v.MinBuyNum), stepNum, stepPrice),
			})
			*v.MinBuyNum++
		}
	}
	warehouseBoxes := int64(0)
	transitBoxes := int64(0)
	listDataRsp := make([]types.ListDataItem, 0, len(stockList))
	for _, v := range stockList {
		dataItem := types.ListDataItem{
			Id:         v.Id,
			Production: *v.Production,
			EachBoxNum: *v.EachBoxNum,
			Stick:      *v.Stick,
			Type:       1,
			TakeNum:    1, // 步数
		}
		//设计详情
		designInfo, designOk := mapProductDesign[*v.DesignId]
		sizeId := int64(0)
		optionalId := int64(0)
		if designOk {
			mapKey := l.getMapProductMaterialSizePriceKey(*v.ProductId, *designInfo.MaterialId, *designInfo.SizeId)
			dataItem.DesignSn = *designInfo.Sn
			dataItem.Cover = *designInfo.Cover
			sizeId = *designInfo.SizeId
			optionalId = *designInfo.OptionalId
			dataItem.PriceList = mapProductMaterialSizePrice[mapKey]
		}
		//模型信息
		productModel3dInfo, model3dOk := mapProductModel[optionalId]
		if model3dOk {
			dataItem.Fitting = *productModel3dInfo.Title
			//配件下架
			if *productModel3dInfo.Status == 0 {
				dataItem.IsStop = 3
			}
		}
		//模板信息
		templateInfo, templateOk := mapTemplate[*designInfo.TemplateId]
		if templateOk {
			//模板下架
			if *templateInfo.IsDel == 1 || *templateInfo.Status == 0 {
				dataItem.IsStop = 1
			}
		}
		//尺寸信息
		sizeInfo, sizeOk := mapSize[sizeId]
		if sizeOk {
			dataItem.Size = *sizeInfo.Capacity
			//尺寸下架
			if *sizeInfo.Status == 0 {
				dataItem.IsStop = 1
			}
		}
		//产品信息
		productInfo, productOk := mapProduct[*v.ProductId]
		if productOk {
			dataItem.Sn = *productInfo.Sn
			dataItem.Name = *productInfo.Title
			if *productInfo.IsShelf == 0 || *productInfo.IsDel == 1 {
				dataItem.IsStop = 2
			}
		}
		if sizeFlag {
			coverArr := strings.Split(*designInfo.Cover, ".")
			if len(coverArr) < 2 {
				return resp.SetStatusWithMessage(basic.CodeServiceErr, "cover split slice item count is less than 2")
			}
			dataItem.Cover = fmt.Sprintf("%s_%d.%s", coverArr[0], req.Size, coverArr[1])
		}
		//生产中的箱数
		if *v.EachBoxNum > 0 {
			dataItem.ProductionBox = *v.Production / *v.EachBoxNum
			dataItem.StickBox = *v.Stick / *v.EachBoxNum
		}
		//判断提示类型1 2告急 3没有了
		if *v.Stick <= 0 && *v.Production <= 0 {
			dataItem.Type = 3
		}
		if (*v.Stick+*v.Production) / *v.EachBoxNum <= 3 {
			dataItem.Type = 2
		}
		listDataRsp = append(listDataRsp, dataItem)
		//累加在库数量和运输数量
		if *v.EachBoxNum != 0 {
			warehouseBoxes += *v.Stick / *v.EachBoxNum
			transitBoxes += *v.TransNum / *v.EachBoxNum
		}
	}
	return resp.SetStatusWithMessage(basic.CodeOK, "success", types.GetCloudListRsp{
		WarehouseBoxes: warehouseBoxes,
		TransitBoxes:   transitBoxes,
		MinTakeNum:     3,
		ListData:       listDataRsp,
		Meta: types.Meta{
			TotalCount:  total,
			PageCount:   int64(math.Ceil(float64(total) / float64(req.PageSize))),
			CurrentPage: req.Page,
			PerPage:     req.PageSize,
		},
	})
}

func (l *GetCloudListLogic) getMapProductMaterialSizePriceKey(productId int64, materialId int64, sizeId int64) string {
	return fmt.Sprintf("%d-%d-%d", productId, materialId, sizeId)
}