package co.yixiang.yshop.module.product.service.storeproduct;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import co.yixiang.yshop.framework.common.constant.ShopConstants;
import co.yixiang.yshop.framework.common.enums.ShopCommonEnum;
import co.yixiang.yshop.framework.common.util.json.JsonUtils;
import co.yixiang.yshop.module.product.controller.app.campaigninfo.vo.AppCampaignSkuRespVO;
import co.yixiang.yshop.module.product.controller.app.coupon.vo.AppCouponDetailRespVO;
import co.yixiang.yshop.module.product.controller.app.product.param.AppStoreProductQueryParam;
import co.yixiang.yshop.module.product.controller.app.product.vo.*;
import co.yixiang.yshop.module.product.convert.storeproduct.StoreProductConvert;
import co.yixiang.yshop.module.product.dal.dataobject.shippingtemplates.ShippingTemplatesDO;
import co.yixiang.yshop.module.product.dal.dataobject.storeproduct.StoreProductDO;
import co.yixiang.yshop.module.product.dal.dataobject.storeproductattrvalue.StoreProductAttrValueDO;
import co.yixiang.yshop.module.product.dal.dataobject.storeproductrelation.StoreProductRelationDO;
import co.yixiang.yshop.module.product.dal.mysql.campaigndetail.CampaignDetailMapper;
import co.yixiang.yshop.module.product.dal.mysql.storeproduct.StoreProductMapper;
import co.yixiang.yshop.module.product.dal.mysql.storeproductattrvalue.StoreProductAttrValueMapper;
import co.yixiang.yshop.module.product.dal.mysql.storeproductrelation.StoreProductRelationMapper;
import co.yixiang.yshop.module.product.dal.redis.RedisKeyConstants;
import co.yixiang.yshop.module.product.enums.ProductConstants;
import co.yixiang.yshop.module.product.enums.coupon.CouponTypeEnum;
import co.yixiang.yshop.module.product.enums.product.*;
import co.yixiang.yshop.module.product.service.campaigninfo.AppCampaignInfoService;
import co.yixiang.yshop.module.product.service.productcoupon.AppCouponService;
import co.yixiang.yshop.module.product.service.shippingtemplates.ShippingTemplatesService;
import co.yixiang.yshop.module.product.service.storeproductattr.AppStoreProductAttrService;
import co.yixiang.yshop.module.product.service.storeproductattrvalue.StoreProductAttrValueService;
import co.yixiang.yshop.module.product.service.storeproductrelation.AppStoreProductRelationService;
import co.yixiang.yshop.module.product.service.storeproductreply.AppStoreProductReplyService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static co.yixiang.yshop.framework.common.exception.util.ServiceExceptionUtil.exception;
import static co.yixiang.yshop.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static co.yixiang.yshop.module.product.enums.ErrorCodeConstants.PRODUCT_STOCK_LESS;
import static co.yixiang.yshop.module.product.enums.ErrorCodeConstants.STORE_PRODUCT_NOT_EXISTS;

/**
 * 商品 AppService 实现类
 *
 * @author yshop
 */
@Slf4j
@Service
@Validated
public class AppStoreProductServiceImpl extends ServiceImpl<StoreProductMapper, StoreProductDO> implements AppStoreProductService {

    @Resource
    private AppStoreProductAttrService appStoreProductAttrService;
    @Resource
    private AppStoreProductRelationService appStoreProductRelationService;
    @Resource
    private AppStoreProductReplyService appStoreProductReplyService;
    @Resource
    private ShippingTemplatesService shippingTemplatesService;
    @Resource
    private StoreProductAttrValueService storeProductAttrValueService;
    @Resource
    private StoreProductAttrValueMapper storeProductAttrValueMapper;

    @Resource
    private StoreProductRelationMapper storeProductRelationMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private AppCouponService appCouponService;

    @Resource
    private CampaignDetailMapper campaignDetailMapper;

    @Resource
    private AppCampaignInfoService appCampaignInfoService;

    /**
     * 最近历史搜索的大小
     */
    public static final Integer CURRENT_SEARCH_SIZE = 10;

    /**
     * 商品列表
     *
     * @param page  页码
     * @param limit 条数
     * @param order ProductEnum
     * @return List
     */
    @Override
    public List<AppStoreProductRespVo> getList(int page, int limit, int order) {
        LambdaQueryWrapper<StoreProductDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreProductDO::getIsShow, ShopCommonEnum.SHOW.getValue())
                //.eq(YxStoreProduct::getIsDel,ShopCommonEnum.DELETE_0.getValue())
                .orderByDesc(StoreProductDO::getSort);
        wrapper.eq(StoreProductDO::getIsIntegral, 0);
        // order
        switch (ProductEnum.toType(order)) {
            //精品推荐
            case TYPE_1:
                wrapper.eq(StoreProductDO::getIsBest,
                        ShopCommonEnum.YES.getValue());
                break;
            //首发新品
            case TYPE_3:
                wrapper.eq(StoreProductDO::getIsNew,
                        ShopCommonEnum.YES.getValue());
                break;
            // 猜你喜欢
            case TYPE_4:
                wrapper.eq(StoreProductDO::getIsBenefit,
                        ShopCommonEnum.YES.getValue());
                break;
            // 热门榜单
            case TYPE_2:
                wrapper.eq(StoreProductDO::getIsHot,
                        ShopCommonEnum.YES.getValue());
                break;
            default:
        }
        Page<StoreProductDO> pageModel = new Page<>(page, limit);

        IPage<StoreProductDO> pageList = this.baseMapper.selectPage(pageModel, wrapper);

        return StoreProductConvert.INSTANCE.convertList03(pageList.getRecords());
    }


    /**
     * 商品列表
     *
     * @param productQueryParam AppStoreProductQueryParam
     * @return list
     */
    @Override
    public List<AppStoreProductRespVo> getGoodsList(AppStoreProductQueryParam productQueryParam) {

        LambdaQueryWrapper<StoreProductDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreProductDO::getIsShow, ShopCommonEnum.SHOW.getValue());

        if (productQueryParam.getIsIntegral() != null) {
            wrapper.eq(StoreProductDO::getIsIntegral, productQueryParam.getIsIntegral());
        }
        //多字段模糊查询分类搜索
        if (StrUtil.isNotBlank(productQueryParam.getSid()) &&
                !ShopConstants.YSHOP_ZERO.equals(productQueryParam.getSid())) {
            wrapper.eq(StoreProductDO::getCateId, productQueryParam.getSid());
        }
        // 查询优惠券可用商品
        if (productQueryParam.getCouponId() != null && productQueryParam.getCouponId() != 0) {
            List<Long> productIdList = appCouponService.getCouponProductList(productQueryParam.getCouponId());
            wrapper.in(CollectionUtils.isNotEmpty(productIdList), StoreProductDO::getId, productIdList);
        }
        //关键字搜索
        if (StrUtil.isNotEmpty(productQueryParam.getKeyword())) {
            wrapper.and(wrapper1 -> {
                wrapper1.or();
                wrapper1.like(StoreProductDO::getStoreName, productQueryParam.getKeyword());
                wrapper1.or();
                wrapper1.like(StoreProductDO::getStoreInfo, productQueryParam.getKeyword());
                wrapper1.or();
                wrapper1.like(StoreProductDO::getKeyword, productQueryParam.getKeyword());
            });
            //缓存用户历史搜索
            Long userId = getLoginUserId();
            addUserSearchHistory(userId, productQueryParam.getKeyword());
            // 缓存搜索记录
            addSearchPopular(productQueryParam.getKeyword());
        }
        //新品搜索
        if (StrUtil.isNotBlank(productQueryParam.getNews()) &&
                !ShopConstants.YSHOP_ZERO.equals(productQueryParam.getNews())) {
            wrapper.eq(StoreProductDO::getIsNew, ShopCommonEnum.NEW.getValue());
        }

        //销量查询
        if (StrUtil.isNotBlank(productQueryParam.getSales()) &&
                !ShopConstants.YSHOP_ZERO.equals(productQueryParam.getSales())) {
            wrapper.orderByDesc(StoreProductDO::getSales);
        }
        if (productQueryParam.getIsDistribution() != null) {
            wrapper.eq(StoreProductDO::getIsDistribution, productQueryParam.getIsDistribution());
        }

        Page<StoreProductDO> pageModel = new Page<>(productQueryParam.getPage(),
                productQueryParam.getLimit());

        IPage<StoreProductDO> pageList = this.baseMapper.selectPage(pageModel, wrapper);
        List<AppStoreProductRespVo> list = StoreProductConvert.INSTANCE.convertList03(pageList.getRecords());
        if (CollectionUtils.isNotEmpty(list)) {
            // 返回活动信息
            List<Long> productIds = list.stream().map(AppStoreProductRespVo::getId).collect(Collectors.toList());
            List<AppCampaignSkuRespVO> campaignDetailDOS =
                    campaignDetailMapper.getCampaignSkus(productIds);
            if (CollectionUtils.isNotEmpty(campaignDetailDOS)) {
                Map<Long, List<AppCampaignSkuRespVO>> campaignDetailMap =
                        campaignDetailDOS.stream().collect(Collectors.groupingBy(AppCampaignSkuRespVO::getProductId));
                for (AppStoreProductRespVo respVo : list) {
                    List<AppCampaignSkuRespVO> detailDOS = campaignDetailMap.get(respVo.getId());
                    if (CollectionUtils.isEmpty(detailDOS)) continue;
                    // 默认显示第一个
                    AppCampaignSkuRespVO skuRespVO = detailDOS.get(0);
                    respVo.setCampaignType(skuRespVO.getType());
                    respVo.setSkuId(skuRespVO.getSkuId());
                    respVo.setProductAttrUnique(skuRespVO.getProductAttrUnique());
                    respVo.setCampaignPrice(skuRespVO.getPrice());
                    respVo.setCampaignStock(skuRespVO.getStock());
                    respVo.setCampaignTotal(skuRespVO.getTotal());
                    respVo.setPerson(skuRespVO.getPerson());
                    respVo.setDiscount(skuRespVO.getDiscount());
                    respVo.setCampaignState(skuRespVO.getState());
                }
            }
        }

        return list;
    }


    /**
     * 商品详情
     *
     * @param vo
     * @param uid 用户id
     * @return ProductVo
     */
    @Override
    public AppProductVo goodsDetail(AppStoreProductDetailReqVo vo, Long uid) {
        Long id = vo.getProductId();
        LambdaQueryWrapper<StoreProductDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreProductDO::getId, id);
        StoreProductDO storeProduct = this.baseMapper.selectOne(wrapper);
        if (ObjectUtil.isNull(storeProduct)) {
            throw exception(STORE_PRODUCT_NOT_EXISTS);
        }

        //获取商品sku
        Map<String, Object> returnMap = appStoreProductAttrService.getProductAttrDetail(id);
        AppProductVo productVo = new AppProductVo();
        productVo.setIsShow(storeProduct.getIsShow());
        AppStoreProductRespVo storeProductQueryVo = StoreProductConvert.INSTANCE.convert01(storeProduct);

        //设置销量
        storeProductQueryVo.setSales(storeProductQueryVo.getSales() + storeProduct.getFicti());

        if (uid > 0) {
            //设置VIP价格
            //todo

            //收藏
            boolean isCollect = appStoreProductRelationService.isProductRelation(id, uid, RelationCateEnum.COMMON.getValue());
            storeProductQueryVo.setUserCollect(isCollect);
        }
        //总条数
        Long totalCount = appStoreProductReplyService.productReplyCount(id);
        productVo.setReplyCount(totalCount);

        //评价
        AppStoreProductReplyQueryVo storeProductReplyQueryVo = appStoreProductReplyService.getReply(id);
        productVo.setReply(storeProductReplyQueryVo);

        //好评比例
        String replyPer = appStoreProductReplyService.replyPer(id);
        productVo.setReplyChance(replyPer);

        //获取运费模板名称
        String tempName = "";
        if (storeProduct.getPostage().compareTo(BigDecimal.ZERO) == 0 && storeProduct.getTempId() == 0) {
            tempName = ProductConstants.FREE_POSTAGE;
        } else {
            ShippingTemplatesDO shippingTemplates = shippingTemplatesService.getById(storeProduct.getTempId());
            if (ObjectUtil.isNotNull(shippingTemplates)) {
                tempName = shippingTemplates.getName();
            } else {
                tempName = ProductConstants.POSTAGE_TEMP_NOT;
            }

        }
        productVo.setTempName(tempName);

        //设置商品相关信息
        productVo.setStoreInfo(storeProductQueryVo);
        List<AppStoreProductAttrQueryVo> attrList = JsonUtils.parseObject(JsonUtils.toJsonString(returnMap.get("productAttr")),
                new TypeReference<List<AppStoreProductAttrQueryVo>>() {
                });
        productVo.setProductAttr(attrList);
        Map<String, AppStoreProductAttrValueVo> attrValueMap = JsonUtils.parseObject(JsonUtils.toJsonString(returnMap.get("productValue")),
                new TypeReference<Map<String, AppStoreProductAttrValueVo>>() {
                });
        if (SpecTypeEnum.SINGLE_SPECS.getValue().equals(storeProduct.getSpecType())) {
            attrValueMap.values().forEach(res -> res.setImage(storeProduct.getImage()));
        }
        // 设置营销活动信息
        if (CollectionUtils.isNotEmpty(attrValueMap.values())) {
            // 查询该商品的营销活动
            List<AppCampaignSkuRespVO> campaignSkuRespVOS =
                    campaignDetailMapper.getCampaignSkus(Arrays.asList(vo.getProductId()));
            if (CollectionUtils.isNotEmpty(campaignSkuRespVOS)) {
                for (AppCampaignSkuRespVO campaignSkuRespVO : campaignSkuRespVOS) {
                    AppStoreProductAttrValueVo valueVo = attrValueMap.get(campaignSkuRespVO.getSku());
                    if (ObjectUtil.isNull(valueVo)) continue;
                    valueVo.setCampaignId(campaignSkuRespVO.getId());
                    valueVo.setCampaignDetailId(campaignSkuRespVO.getDetailId());
                    valueVo.setCampaignStock(campaignSkuRespVO.getStock());
                    valueVo.setCampaignPrice(campaignSkuRespVO.getPrice());
                    valueVo.setCampaignStock(campaignSkuRespVO.getStock());
                    valueVo.setCampaignTotal(campaignSkuRespVO.getTotal());
                    valueVo.setCampaignType(campaignSkuRespVO.getType());
                    valueVo.setDiscount(campaignSkuRespVO.getDiscount());
                    valueVo.setPerson(campaignSkuRespVO.getPerson());
                    valueVo.setStartTime(campaignSkuRespVO.getStartTime());
                    valueVo.setEndTime(campaignSkuRespVO.getEndTime());
                    valueVo.setCampaignState(campaignSkuRespVO.getState());
                }
            }
        }
        productVo.setProductValue(attrValueMap);

        //添加足迹,先删除之前的，更新时间
        LambdaQueryWrapper<StoreProductRelationDO> productDOLambdaQueryWrapper = new LambdaQueryWrapper<>();
        storeProductRelationMapper.delete(
                productDOLambdaQueryWrapper.eq(StoreProductRelationDO::getProductId, id)
                        .eq(StoreProductRelationDO::getUid, uid)
                        .eq(StoreProductRelationDO::getType, RelationEnum.FOOT.getValue()));
        StoreProductRelationDO storeProductRelationDO = StoreProductRelationDO.builder()
                .productId(id)
                .uid(uid)
                .category("common")
                .type(RelationEnum.FOOT.getValue())
                .build();
        storeProductRelationMapper.insert(storeProductRelationDO);

        // 设置优惠券信息
        List<AppCouponDetailRespVO> couponDetailList = appCouponService.receiveList(id, uid);
        if (CollectionUtils.isNotEmpty(couponDetailList)) {
            AppCouponDetailRespVO couponDetail = couponDetailList.get(0);
            if (CouponTypeEnum.FULL_REDUCTION.getValue().equals(couponDetail.getCouponType())) {
                productVo.setCouponSplicing("满" + couponDetail.getThreshold() + "元减" + couponDetail.getCouponValue());
            } else {
                productVo.setCouponSplicing("满" + couponDetail.getThreshold() + "元" + couponDetail.getDiscount() + "折");
            }

        }
        return productVo;
    }


    /**
     * 返回普通商品库存
     *
     * @param productId 商品id
     * @param unique    sku唯一值
     * @return int
     */
    @Override
    public int getProductStock(Long productId, String unique, String type) {
        StoreProductAttrValueDO storeProductAttrValue = storeProductAttrValueService
                .getOne(Wrappers.<StoreProductAttrValueDO>lambdaQuery()
                        .eq(StoreProductAttrValueDO::getUnique, unique)
                        .eq(StoreProductAttrValueDO::getProductId, productId));

        if (storeProductAttrValue == null) {
            return 0;
        }
        if (ProductTypeEnum.PINK.getValue().equals(type)) {
            return storeProductAttrValue.getPinkStock();
        } else if (ProductTypeEnum.SECKILL.getValue().equals(type)) {
            return storeProductAttrValue.getSeckillStock();
        }
        return storeProductAttrValue.getStock();

    }

    /**
     * 获取单个商品
     *
     * @param id 商品id
     * @return YxStoreProductQueryVo
     */
    @Override
    public AppStoreProductRespVo getStoreProductById(Long id) {
        return StoreProductConvert.INSTANCE.convert01(this.baseMapper.selectById(id));
    }

    @Override
    public List<AppStoreProductRespVo> getStoreProductByIds(List<Long> ids) {
        return StoreProductConvert.INSTANCE.convertList03(this.baseMapper.selectBatchIds(ids));
    }


    /**
     * 减少库存与增加销量
     *
     * @param num       数量
     * @param productId 商品id
     * @param unique    sku
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void decProductStock(int num, Long productId, String unique, Long activityId, String type) {


        int res = storeProductAttrValueMapper.decStockIncSales(num, productId, unique);

        if (res == 0) {
            throw exception(PRODUCT_STOCK_LESS);
        }

        int product = this.baseMapper.decStockIncSales(num, productId);
        if (product == 0) {
            throw exception(PRODUCT_STOCK_LESS);
        }


    }

    @Override
    public void incSales(Integer num, Long productId) {
        this.baseMapper.incSales(num, productId);
    }


    /**
     * 增加库存 减少销量
     *
     * @param num       数量
     * @param productId 商品id
     * @param unique    sku唯一值
     * @param type      回退类型
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void incProductStock(Integer num, Long productId, String unique, Integer type) {
        log.info("回退库存类型：{}", type);
        if (StockBackTypeEnum.NORMAL.getValue().equals(type)) {
            //处理属性sku
            if (StrUtil.isNotEmpty(unique)) {
                storeProductAttrValueMapper.incStockDecSales(num, productId, unique);
            }
            //更新商品
            this.baseMapper.incStockDecSales(num, productId);
        } else {
            // 增加活动库存
            appCampaignInfoService.backStock(unique, num);
            //更新商品
            this.baseMapper.incSales(-num, productId);
        }
    }

    private void addUserSearchHistory(Long userId, String keyWord) {
        String key = RedisKeyConstants.YSHOP_USER_SEARCH_HISTORY_KEY.formatKey(userId);
        //历史搜索记录保持30天，30天不登录查询则自动过期
        stringRedisTemplate.expire(key, 30, TimeUnit.DAYS);

        ZSetOperations<String, String> zSet = stringRedisTemplate.opsForZSet();
        //由于zset 的集合特性当插入已经存在的 v 值 (搜索记录) 时只会更新score 值，
        zSet.add(key, keyWord, Instant.now().getEpochSecond());

        //只得到当前用户的最近搜索记录,注意这里必须保证set集合的顺序
        Set<String> userRecentSearches = listRecentSearch(userId);

        if (userRecentSearches.size() > CURRENT_SEARCH_SIZE) {
            //获取到最开始浏览的第一条
            String firstSearch = userRecentSearches.stream().reduce((first, second) -> second).orElse(null);
            //删除最开始浏览的第一条
            zSet.remove(key, firstSearch);
        }
    }


    /**
     * 历史最近搜索列表
     *
     * @return 历史搜索列表
     */
    @Override
    public Set<String> listRecentSearch(Long userId) {
        String key = RedisKeyConstants.YSHOP_USER_SEARCH_HISTORY_KEY.formatKey(userId);
        Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().reverseRangeWithScores(key, 0, -1);
        return Optional.ofNullable(typedTuples)
                .map(tuples -> tuples.stream()
                        .map(ZSetOperations.TypedTuple::getValue)
                        .filter(Objects::nonNull)
                        .limit(20)
                        .collect(Collectors.collectingAndThen(
                                Collectors.toCollection(LinkedHashSet::new), LinkedHashSet::new)))
                .orElseGet(LinkedHashSet::new);
    }


    @Override
    public void removeSearchHistoryAll(Long userId) {
        stringRedisTemplate.delete(RedisKeyConstants.YSHOP_USER_SEARCH_HISTORY_KEY.formatKey(userId));
    }

    @Override
    public Set<String> searchPopular(Long start, Long end) {
        String key = RedisKeyConstants.YSHOP_POPULAR_SEARCH_RECORDS_KEY.formatKey();
        return stringRedisTemplate.opsForZSet().reverseRange(key, start, end);
    }

    /**
     * 缓存搜索记录
     *
     * @param keyWord 搜索关键字
     */
    private void addSearchPopular(String keyWord) {
        String key = RedisKeyConstants.YSHOP_POPULAR_SEARCH_RECORDS_KEY.formatKey();
        stringRedisTemplate.opsForZSet().incrementScore(key, keyWord, 1);
    }

}
