package gmodel

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"fusenapi/constants"
	"sort"
)

// 阶梯价结构
type StepPriceJsonStruct struct {
	PriceRange []struct {
		Label         string `json:"label"`
		Price         int64  `json:"price"`
		EndQuantity   int64  `json:"end_quantity"`
		StartQuantity int64  `json:"start_quantity"`
	} `json:"price_range"`
	MinBuyUnitsNum int64 `json:"min_buy_units_num"`
}

func (d *FsProductModel3dModel) FindOne(ctx context.Context, id int64, fields ...string) (resp *FsProductModel3d, err error) {
	db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`id` = ? and `status` =? ", id, 1)
	if len(fields) > 0 {
		db = db.Select(fields[0])
	}
	err = db.Take(&resp).Error
	return resp, err
}
func (d *FsProductModel3dModel) GetAllByIds(ctx context.Context, ids []int64, orderBy string, fields ...string) (resp []FsProductModel3d, err error) {
	if len(ids) == 0 {
		return
	}
	db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`id` in (?) and `status` = ?", ids, 1)
	if len(fields) > 0 {
		db = db.Select(fields[0])
	}
	if orderBy != "" {
		db = db.Order(orderBy)
	}
	err = db.Find(&resp).Error
	return resp, err
}
func (d *FsProductModel3dModel) GetAllByIdsWithoutStatus(ctx context.Context, ids []int64, fields ...string) (resp []FsProductModel3d, err error) {
	if len(ids) == 0 {
		return
	}
	db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`id` in (?) and `status` = ?", ids, 1)
	if len(fields) > 0 {
		db = db.Select(fields[0])
	}
	err = db.Find(&resp).Error
	return resp, err
}
func (d *FsProductModel3dModel) GetAllByIdsTag(ctx context.Context, ids []int64, tag int64, fields ...string) (resp []FsProductModel3d, err error) {
	if len(ids) == 0 {
		return
	}
	db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`id` in (?) and `status` = ? and `tag` = ?", ids, 1, tag)
	if len(fields) > 0 {
		db = db.Select(fields[0])
	}
	err = db.Find(&resp).Error
	return resp, err
}

type Get3dModelsByParamReq struct {
	Tag       int64
	ProductId int64
}

func (d *FsProductModel3dModel) Get3dModelsByParam(ctx context.Context, req Get3dModelsByParamReq) (resp []FsProductModel3d, err error) {
	if req.ProductId == 0 && req.Tag == 0 {
		return nil, nil
	}
	db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`status` = ?", 1)
	if req.ProductId > 0 {
		db = db.Where("`product_id` =? ", req.ProductId)
	}
	if req.Tag > 0 {
		db = db.Where("`tag` =? ", req.Tag)
	}
	err = db.Find(&resp).Error
	return resp, err
}
func (d *FsProductModel3dModel) Update(ctx context.Context, id int64, data *FsProductModel3d) error {
	return d.db.WithContext(ctx).Where("`id` = ? and `status` =?  ", id, 1).Updates(&data).Error
}
func (d *FsProductModel3dModel) GetAllBySizeIdsTag(ctx context.Context, sizeIds []int64, tag int64, fields ...string) (resp []FsProductModel3d, err error) {
	if len(sizeIds) == 0 {
		return
	}
	db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`size_id` in (?)  and `tag` = ? and `status` = ?", sizeIds, tag, 1)
	if len(fields) != 0 {
		db = db.Select(fields[0])
	}
	err = db.Find(&resp).Error
	return resp, err
}
func (d *FsProductModel3dModel) GetAll(ctx context.Context) (resp []FsProductModel3d, err error) {
	err = d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`status` = ?", 1).Find(&resp).Error
	return resp, err
}

type GetGroupPartListByProductIdsRsp struct {
	PartList  string `json:"part_list"`
	ProductId int64  `json:"product_id"`
}

func (d *FsProductModel3dModel) GetGroupPartListByProductIds(ctx context.Context, productIds []int64) (resp []GetGroupPartListByProductIdsRsp, err error) {
	if len(productIds) == 0 {
		return
	}
	err = d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`product_id` in(?) and `status` =? ", productIds, 1).
		Select("product_id,group_concat(part_list) as part_list").
		Group("product_id").Find(&resp).Error
	return resp, err
}
func (d *FsProductModel3dModel) FindOneJoinSize(ctx context.Context, productId int64) (resp FsProductModel3d, err error) {
	err = d.db.WithContext(ctx).Table(d.name+"as m").Joins("left join fs_product_size as s on m.size_id = s.id").
		Select("m.*").
		Where("m.product_id = ?", productId).
		Where("(s.status= ? and m.tag = ?)", 1, 1).
		Order("s.sort ASC").Take(&resp).Error
	return resp, err
}

func (d *FsProductModel3dModel) GetOneBySizeIdTag(ctx context.Context, sizeId int64, tag int64, fields ...string) (resp *FsProductModel3d, err error) {
	db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).
		Where("`size_id` = ?  and `tag` = ? and `status` = ?", sizeId, tag, 1).
		Order("sort DESC")
	if len(fields) != 0 {
		db = db.Select(fields[0])
	}
	err = db.Take(&resp).Error
	return resp, err
}

func (d *FsProductModel3dModel) GetAllByProductIdTag(ctx context.Context, productId int64, tag int64, fields ...string) (resp []FsProductModel3d, err error) {
	db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).
		Where("`product_id` = ?  and `tag` = ? and `status` = ?", productId, tag, 1).
		Order("sort DESC")
	if len(fields) != 0 {
		db = db.Select(fields[0])
	}
	err = db.Find(&resp).Error
	return resp, err
}
func (d *FsProductModel3dModel) FindOneByProductIdSizeIdTag(ctx context.Context, productId, sizeId, tag int64, fields ...string) (resp *FsProductModel3d, err error) {
	db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).
		Where("`product_id` = ? and `size_id` = ?  and `tag` = ? and `status` = ?", productId, sizeId, tag, 1).
		Order("sort DESC")
	if len(fields) != 0 {
		db = db.Select(fields[0])
	}
	err = db.Take(&resp).Error
	return resp, err
}

func (d *FsProductModel3dModel) GetAllByProductIdsTags(ctx context.Context, productIds []int64, tags []int, fields ...string) (resp []FsProductModel3d, err error) {
	if len(productIds) == 0 || len(tags) == 0 {
		return
	}
	db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).
		Where("`product_id` in (?)  and `tag` in (?) and `status` = ?", productIds, tags, 1).
		Order("sort DESC")
	if len(fields) != 0 {
		db = db.Select(fields[0])
	}
	err = db.Find(&resp).Error
	return resp, err
}

// 获取每个产品最低价格
func (d *FsProductModel3dModel) GetProductMinPrice(modelList []FsProductModel3d, mapProductMinPrice map[int64]int64) error {
	mapModelMinPrice := make(map[int64]int64)
	//每个模型/配件存储最小价格
	for _, modelInfo := range modelList {
		switch *modelInfo.Tag {
		case constants.TAG_MODEL: //模型
			if modelInfo.StepPrice == nil || len(*modelInfo.StepPrice) == 0 {
				mapModelMinPrice[modelInfo.Id] = 0
				continue
			}
			var stepPrice StepPriceJsonStruct
			if err := json.Unmarshal(*modelInfo.StepPrice, &stepPrice); err != nil {
				return errors.New(fmt.Sprintf("failed to parse model step price:%d", modelInfo.Id))
			}
			lenRange := len(stepPrice.PriceRange)
			if lenRange == 0 {
				mapModelMinPrice[modelInfo.Id] = 0
				continue
			}
			sort.SliceStable(stepPrice.PriceRange, func(i, j int) bool {
				return stepPrice.PriceRange[i].Price > stepPrice.PriceRange[j].Price
			})
			mapModelMinPrice[modelInfo.Id] = stepPrice.PriceRange[lenRange-1].Price
		case constants.TAG_PARTS: //配件
			mapModelMinPrice[modelInfo.Id] = *modelInfo.Price
		}
	}
	//给产品存储最小价格
	for _, v := range modelList {
		if *v.Tag != constants.TAG_MODEL {
			continue
		}
		itemPrice := mapModelMinPrice[v.Id]
		if *v.PartId > 0 {
			if fittingPrice, ok := mapModelMinPrice[*v.PartId]; ok {
				itemPrice += fittingPrice
			}
		}
		if minPrice, ok := mapProductMinPrice[*v.ProductId]; ok {
			if itemPrice < minPrice {
				mapProductMinPrice[*v.ProductId] = itemPrice
			}
			continue
		}
		mapProductMinPrice[*v.ProductId] = itemPrice
	}
	return nil
}
func (d *FsProductModel3dModel) GetAllByProductIdTags(ctx context.Context, productId int64, tags []int64, fields ...string) (resp []FsProductModel3d, err error) {
	db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`product_id`= ? and `tag` in(?) and `status` = ?", productId, tags, 1)
	if len(fields) != 0 {
		db = db.Select(fields[0])
	}
	err = db.Find(&resp).Error
	return resp, err
}