package logic

import (
	"context"
	"encoding/json"
	"errors"
	"fusenapi/constants"
	"fusenapi/model/gmodel"
	"fusenapi/server/product/internal/svc"
	"fusenapi/server/product/internal/types"
	"fusenapi/utils/auth"
	"fusenapi/utils/basic"
	"fusenapi/utils/format"
	"fusenapi/utils/image"
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/core/stores/sqlc"
	"gorm.io/gorm"
	"math"
	"sort"
	"strings"
)

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

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

// 获取产品列表
func (l *GetProductListLogic) GetProductList(req *types.GetProductListReq, userinfo *auth.UserInfo) (resp *basic.Response) {
	//如果是demo
	if req.IsDemo == 1 {
		var demo types.GetProductListRsp
		if err := json.Unmarshal([]byte(constants.PRODUCT_LIST_DEMO), &demo); err != nil {
			logx.Error(err)
			return resp.SetStatusWithMessage(basic.CodeServiceErr, "demo data format err")
		}
		return resp.SetStatusWithMessage(basic.CodeOK, "success", demo)
	}
	if req.Page <= 0 {
		req.Page = constants.DEFAULT_PAGE
	}
	//获取合适尺寸
	if req.Size > 0 {
		req.Size = image.GetCurrentSize(req.Size)
	}
	pageSize := constants.DEFAULT_PAGE_SIZE
	//查询用户信息(不用判断存在)
	userModel := gmodel.NewFsUserModel(l.svcCtx.MysqlConn)
	user, err := userModel.FindUserById(l.ctx, userinfo.UserId)
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "get user info err")
	}
	//查询符合的产品列表
	productModel := gmodel.NewFsProductModel(l.svcCtx.MysqlConn)
	productList, total, err := productModel.GetProductListByTypeIds(l.ctx, []int64{req.Cid}, int(req.Page), pageSize, "sort-desc")
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get product list")
	}
	productLen := len(productList)
	if productLen == 0 {
		return resp.SetStatusWithMessage(basic.CodeOK, "success")
	}
	//提取产品ids
	productIds := make([]int64, 0, productLen)
	for _, v := range productList {
		productIds = append(productIds, v.Id)
	}
	productPriceModel := gmodel.NewFsProductPriceModel(l.svcCtx.MysqlConn)
	productPriceList, err := productPriceModel.GetSimplePriceListByProductIds(l.ctx, productIds)
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get product min price list")
	}
	//存储产品最小价格
	mapProductMinPrice := make(map[int64]int64)
	for _, v := range productPriceList {
		priceStrSlic := strings.Split(v.Price, ",")
		priceSlice, err := format.StrSlicToIntSlice(priceStrSlic)
		if err != nil {
			logx.Error(err)
			return resp.SetStatusWithMessage(basic.CodeServiceErr, err.Error())
		}
		if len(priceSlice) == 0 {
			continue
		}
		sort.Ints(priceSlice)
		mapProductMinPrice[v.ProductId] = int64(priceSlice[0])
	}
	//获取模板
	productTemplateModel := gmodel.NewFsProductTemplateV2Model(l.svcCtx.MysqlConn)
	productTemplatesV2, err := productTemplateModel.FindAllByProductIds(l.ctx, productIds)
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "get product template_v2 err")
	}
	mapProductTemplate := make(map[int64]struct{})
	for _, v := range productTemplatesV2 {
		mapProductTemplate[*v.ProductId] = struct{}{}
	}
	//获取分类
	tagsModel := gmodel.NewFsTagsModel(l.svcCtx.MysqlConn)
	tagInfo, err := tagsModel.FindOne(l.ctx, req.Cid)
	if err != nil && !errors.Is(err, sqlc.ErrNotFound) {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return resp.SetStatusWithMessage(basic.CodeServiceErr, "tag is not exists")
		}
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "get tag err")
	}
	//获取产品尺寸数量
	productSizeModel := gmodel.NewFsProductSizeModel(l.svcCtx.MysqlConn)
	productSizeCountList, err := productSizeModel.GetGroupProductSizeByStatus(l.ctx, productIds, 1)
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "get product size count err")
	}
	mapProductSizeCount := make(map[int64]int64)
	for _, v := range productSizeCountList {
		mapProductSizeCount[v.ProductId] = v.Num
	}
	//拼接返回
	itemList := make([]types.Items, 0, productLen)
	for _, v := range productList {
		minPrice, ok := mapProductMinPrice[v.Id]
		_, tmpOk := mapProductTemplate[v.Id]
		//无最小价格则不显示 || 没有模板也不显示
		if !ok || !tmpOk {
			continue
		}
		sizeNum := int64(0)
		if mapSizeNum, ok := mapProductSizeCount[v.Id]; ok {
			sizeNum = mapSizeNum
		}
		item := types.Items{
			Id:       v.Id,
			Sn:       *v.Sn,
			Title:    *v.Title,
			Intro:    *v.Intro,
			IsEnv:    *v.IsProtection,
			IsMicro:  *v.IsMicrowave,
			SizeNum:  uint32(sizeNum),
			MinPrice: minPrice,
		}
		//千人千面处理
		r := image.ThousandFaceImageFormatReq{
			Size:           int(req.Size),
			IsThousandFace: 0,
			Cover:          *v.Cover,
			CoverImg:       *v.CoverImg,
			CoverDefault:   *v.CoverImg,
			ProductId:      v.Id,
			UserId:         user.Id,
		}
		if user.Id != 0 {
			r.IsThousandFace = int(*user.IsThousandFace)
		}
		image.ThousandFaceImageFormat(&r)
		item.Cover = r.Cover
		item.CoverImg = r.CoverImg
		item.CoverDefault = r.CoverDefault
		itemList = append(itemList, item)
	}
	return resp.SetStatusWithMessage(basic.CodeOK, "success", types.GetProductListRsp{
		Ob: types.Ob{
			Items: itemList,
			Meta: types.Meta{
				TotalCount:  total,
				PageCount:   int64(math.Ceil(float64(total) / float64(pageSize))),
				CurrentPage: int(req.Page),
				PerPage:     pageSize,
			},
		},
		TypeName:    *tagInfo.Title,
		Description: *tagInfo.Description,
	})
}