package com.liquidnet.service.goblin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsInfoVo;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsSkuInfoVo;
import com.liquidnet.service.goblin.dto.vo.GoblinSqbPerfGoodsVo;
import com.liquidnet.service.goblin.entity.GoblinGoods;
import com.liquidnet.service.goblin.entity.GoblinGoodsSku;
import com.liquidnet.service.goblin.entity.GoblinSqbGoodsExt;
import com.liquidnet.service.goblin.entity.GoblinSqbPerformanceGoods;
import com.liquidnet.service.goblin.mapper.GoblinGoodsMapper;
import com.liquidnet.service.goblin.mapper.GoblinGoodsSkuMapper;
import com.liquidnet.service.goblin.mapper.GoblinSqbGoodsExtMapper;
import com.liquidnet.service.goblin.mapper.GoblinSqbPerformanceGoodsMapper;
import com.liquidnet.service.goblin.param.shouqianba.request.CommonRequest;
import com.liquidnet.service.goblin.param.shouqianba.request.MallListQueryRequest;
import com.liquidnet.service.goblin.param.shouqianba.request.MallProductsQueryRequest;
import com.liquidnet.service.goblin.param.shouqianba.response.data.MallListQueryData;
import com.liquidnet.service.goblin.param.shouqianba.response.data.MallProductsQueryData;
import com.liquidnet.service.goblin.param.shouqianba.request.GoblinSqbGoodsSyncParam;
import com.liquidnet.service.goblin.service.IGoblinShouQianBaService;
import com.liquidnet.service.goblin.service.IGoblinSqbGoodsService;
import com.liquidnet.service.goblin.util.GoblinRedisUtils;
import com.liquidnet.service.goblin.util.GoblinSqbRedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsSpecVo;
import com.liquidnet.service.goblin.service.manage.IGoblinstoreMgtGoodsService;
import com.liquidnet.service.goblin.dto.manage.*;
import com.liquidnet.service.goblin.util.ObjectUtil;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 收钱吧商品同步服务实现
 */
@Slf4j
@Service
public class GoblinSqbGoodsServiceImpl implements IGoblinSqbGoodsService {

    // TODO: 后期移入配置文件
    private static final String SQB_APPID            = "test_appid";
    private static final String SQB_MERCHANT_ID       = "todo_merchant_id";
    private static final String SQB_MERCHANT_USER_ID  = "todo_merchant_user_id";
    private static final String SQB_ROLE              = "super_admin";

    @Autowired
    private GoblinGoodsMapper goblinGoodsMapper;

    @Autowired
    private GoblinGoodsSkuMapper goblinGoodsSkuMapper;

    @Autowired
    private GoblinSqbGoodsExtMapper goblinSqbGoodsExtMapper;

    @Autowired
    private GoblinSqbPerformanceGoodsMapper goblinSqbPerformanceGoodsMapper;

    @Autowired
    private IGoblinShouQianBaService goblinShouQianBaService;

    @Autowired
    private GoblinSqbRedisUtils goblinSqbRedisUtils;

    @Autowired
    private GoblinRedisUtils goblinRedisUtils;

    @Autowired
    private IGoblinstoreMgtGoodsService goblinstoreMgtGoodsService;


    private MallProductsQueryData querySqbProduct(String mallSn, String mallSignature, String sqbProductId) {
        if (StringUtils.isEmpty(mallSn)) return null;
        MallProductsQueryRequest request = new MallProductsQueryRequest();
        request.setAppid(SQB_APPID);
        request.setSeller(buildSeller());
        CommonRequest.Mall mallId = new CommonRequest.Mall();
        mallId.setMallSn(mallSn);
        mallId.setSignature(mallSignature);
        request.setMallID(mallId);
        List<MallProductsQueryData> dataList = goblinShouQianBaService.queryMallProducts(request);
        if (!CollectionUtils.isEmpty(dataList)) {
            for (MallProductsQueryData data : dataList) {
                if (sqbProductId.equals(data.getSpuId())) return data;
            }
        }
        return null;
    }

    @Override
    public ResponseDto<List<GoblinSqbPerfGoodsVo>> getAllMallProducts() {
        try {
            MallListQueryRequest mallRequest = new MallListQueryRequest();
            mallRequest.setAppid(SQB_APPID);
            MallListQueryRequest.Filter filter = new MallListQueryRequest.Filter();
            filter.setSeller(buildSeller());
            mallRequest.setFilter(filter);
            List<MallListQueryData> mallList = goblinShouQianBaService.queryMallList(mallRequest);
            if (CollectionUtils.isEmpty(mallList)) {
                return ResponseDto.success(new ArrayList<>());
            }

            List<GoblinSqbPerfGoodsVo> result = new ArrayList<>();
            for (MallListQueryData mall : mallList) {
                MallProductsQueryRequest productRequest = new MallProductsQueryRequest();
                productRequest.setAppid(SQB_APPID);
                productRequest.setSeller(buildSeller());
                CommonRequest.Mall mallId = new CommonRequest.Mall();
                mallId.setMallSn(mall.getMallSn());
                mallId.setSignature(mall.getSignature());
                productRequest.setMallID(mallId);

                List<MallProductsQueryData> products = goblinShouQianBaService.queryMallProducts(productRequest);
                if (!CollectionUtils.isEmpty(products)) {
                    for (MallProductsQueryData product : products) {
                        List<MallProductsQueryData.Sku> skus = product.getSkuResults();
                        if (CollectionUtils.isEmpty(skus)) {
                            result.add(buildPerfGoodsVo(product, null));
                        } else {
                            for (MallProductsQueryData.Sku sku : skus) {
                                result.add(buildPerfGoodsVo(product, sku));
                            }
                        }
                    }
                }
            }
            return ResponseDto.success(result);
        } catch (Exception e) {
            log.error("[收钱吧] getAllMallProducts 异常", e);
            return ResponseDto.failure("查询收钱吧商品列表失败");
        }
    }

    private GoblinSqbPerfGoodsVo buildPerfGoodsVo(MallProductsQueryData product, MallProductsQueryData.Sku sku) {
        GoblinSqbPerfGoodsVo vo = new GoblinSqbPerfGoodsVo();
        vo.setSpuId(product.getSpuId());
        vo.setSpuName(product.getTitle());
        vo.setCoverPic(!CollectionUtils.isEmpty(product.getConverImages()) ? product.getConverImages().get(0) : "");
        if (sku != null) {
            vo.setSkuId(sku.getSkuId());
            vo.setSkuName(sku.getSkuName() != null ? sku.getSkuName() : sku.getSkuTitle());
            vo.setPrice(sku.getPrice());
        } else {
            vo.setSkuName(product.getTitle());
            vo.setPrice(0L); 
        }
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseDto<String> addGoods(String storeId, List<GoblinSqbGoodsSyncParam> items) {
        if (CollectionUtils.isEmpty(items)) return ResponseDto.failure("新增商品列表不能为空");
        int newCount = 0, existCount = 0, failCount = 0;
        String currentUid = "system";

        for (GoblinSqbGoodsSyncParam item : items) {
            String sqbProductId = item.getSqbProductId(), sqbProductSn = item.getSqbProductSn(),
                    mallSn = item.getMallSn(), mallSignature = item.getMallSignature();
            if (StringUtils.isEmpty(sqbProductId)) {
                failCount++;
                continue;
            }
            try {
                LambdaQueryWrapper<GoblinSqbGoodsExt> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(GoblinSqbGoodsExt::getSqbProductId, sqbProductId);
                if (goblinSqbGoodsExtMapper.selectCount(queryWrapper) > 0) {
                    existCount++;
                    continue;
                }

                MallProductsQueryData productsData = querySqbProduct(mallSn, mallSignature, sqbProductId);
                if (null == productsData) {
                    failCount++;
                    continue;
                }

                // 1. 组装 AddParam
                GoblinStoreMgtGoodsAddParam addParam = buildMgtGoodsAddParam(storeId, productsData);
                
                // 2. 初始化 VOs
                LocalDateTime now = LocalDateTime.now();
                GoblinGoodsInfoVo goodsInfoVo = addParam.initGoodsInfoVo();
                goodsInfoVo.setCreatedBy(currentUid);
                goodsInfoVo.setCreatedAt(now);
                goodsInfoVo.setSpuType(33);
                goodsInfoVo.setVirtualFlg("1");

                ArrayList<GoblinGoodsSpecVo> goodsSpecVoList = ObjectUtil.getGoblinGoodsSpecVoArrayList();
                List<GoblinGoodsSkuInfoVo> goodsSkuInfoVoList = ObjectUtil.getGoblinGoodsSkuInfoVoArrayList();
                addParam.initGoodsSkuInfoVo(goodsInfoVo, goodsSkuInfoVoList, goodsSpecVoList);

                for (GoblinGoodsSkuInfoVo skuVo : goodsSkuInfoVoList) {
                    skuVo.setSkuType(33);
                    skuVo.setVirtualFlg("1");
                    skuVo.setCreatedBy(currentUid);
                    skuVo.setCreatedAt(now);
                }

                // 3. 调用管理端 Service 加商
                goblinstoreMgtGoodsService.goodsAdd(goodsInfoVo, goodsSkuInfoVoList);

                // 4. 建立映射
                List<MallProductsQueryData.Sku> sqbSkus = productsData.getSkuResults();
                if (CollectionUtils.isEmpty(sqbSkus)) {
                    String skuId = goodsSkuInfoVoList.get(0).getSkuId();
                    goblinSqbGoodsExtMapper.insert(buildExt(goodsInfoVo.getSpuId(), skuId, mallSn, sqbProductId, sqbProductSn, null, now));
                } else {
                    for (int i = 0; i < sqbSkus.size(); i++) {
                        String skuId = goodsSkuInfoVoList.get(i).getSkuId();
                        goblinSqbGoodsExtMapper.insert(buildExt(goodsInfoVo.getSpuId(), skuId, mallSn, sqbProductId, sqbProductSn, sqbSkus.get(i).getSkuId(), now));
                    }
                }
                newCount++;
            } catch (Exception e) {
                log.error("[收钱吧新增商品同步] 异常, sqbProductId={}", sqbProductId, e);
                failCount++;
            }
        }
        return ResponseDto.success(String.format("新增完成：同步 %d, 已存在 %d, 失败 %d", newCount, existCount, failCount));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseDto<String> updateGoods(String storeId, List<GoblinSqbGoodsSyncParam> items) {
        if (CollectionUtils.isEmpty(items)) return ResponseDto.failure("更新商品列表不能为空");
        int updateCount = 0, notFoundCount = 0, failCount = 0;
        String currentUid = "system";

        for (GoblinSqbGoodsSyncParam item : items) {
            String sqbProductId = item.getSqbProductId(), mallSn = item.getMallSn(), mallSignature = item.getMallSignature();
            try {
                LambdaQueryWrapper<GoblinSqbGoodsExt> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(GoblinSqbGoodsExt::getSqbProductId, sqbProductId);
                List<GoblinSqbGoodsExt> existingExts = goblinSqbGoodsExtMapper.selectList(queryWrapper);
                if (CollectionUtils.isEmpty(existingExts)) {
                    notFoundCount++;
                    continue;
                }

                String spuId = existingExts.get(0).getSpuId();
                GoblinGoodsInfoVo mgtGoodsInfoVo = goblinRedisUtils.getGoodsInfoVo(spuId);
                if (null == mgtGoodsInfoVo) {
                    notFoundCount++;
                    continue;
                }

                MallProductsQueryData productsData = querySqbProduct(mallSn, mallSignature, sqbProductId);
                if (null == productsData) {
                    failCount++;
                    continue;
                }

                // 2. 编辑 SPU
                GoblinStoreMgtGoodsAddParam addParam = buildMgtGoodsAddParam(storeId, productsData);
                addParam.setSpuId(spuId);
                goblinstoreMgtGoodsService.goodsEditSpu(currentUid, addParam, mgtGoodsInfoVo);

                // 3. 编辑 SKU
                Map<String, String> sqbToSysSkuMap = new HashMap<>();
                for (GoblinSqbGoodsExt ext : existingExts) {
                    sqbToSysSkuMap.put(ext.getSqbSkuId() != null ? ext.getSqbSkuId() : "PLACEHOLDER", ext.getSkuId());
                }

                List<MallProductsQueryData.Sku> sqbSkus = productsData.getSkuResults();
                if (CollectionUtils.isEmpty(sqbSkus)) {
                    String skuId = sqbToSysSkuMap.get("PLACEHOLDER");
                    if (skuId != null) processSkuUpdate(currentUid, storeId, skuId, productsData, null);
                } else {
                    for (MallProductsQueryData.Sku sqbSku : sqbSkus) {
                        String skuId = sqbToSysSkuMap.get(sqbSku.getSkuId());
                        if (skuId != null) processSkuUpdate(currentUid, storeId, skuId, productsData, sqbSku);
                    }
                }
                updateCount++;
            } catch (Exception e) {
                log.error("[收钱吧更新商品同步] 异常, sqbProductId={}", sqbProductId, e);
                failCount++;
            }
        }
        return ResponseDto.success(String.format("更新完成：更新 %d, 未找到 %d, 失败 %d", updateCount, notFoundCount, failCount));
    }

    private void processSkuUpdate(String currentUid, String storeId, String skuId, MallProductsQueryData productsData, MallProductsQueryData.Sku sqbSku) {
        GoblinGoodsSkuInfoVo mgtGoodsSkuInfoVo = goblinRedisUtils.getGoodsSkuInfoVo(skuId);
        if (null == mgtGoodsSkuInfoVo) return;
        
        GoblinGoodsInfoVo mgtGoodsInfoVo = goblinRedisUtils.getGoodsInfoVo(mgtGoodsSkuInfoVo.getSpuId());
        if (null == mgtGoodsInfoVo) return;

        GoblinStoreMgtGoodsEditSkuParam editSkuParam = new GoblinStoreMgtGoodsEditSkuParam();
        editSkuParam.setStoreId(storeId);
        editSkuParam.setSpuId(mgtGoodsSkuInfoVo.getSpuId());
        editSkuParam.setSkuId(skuId);
        editSkuParam.setSkuPic(mgtGoodsSkuInfoVo.getSkuPic());
        if (!CollectionUtils.isEmpty(productsData.getConverImages())) {
            editSkuParam.setSkuPic(productsData.getConverImages().get(0));
        }
        
        if (sqbSku != null) {
            BigDecimal price = BigDecimal.valueOf(sqbSku.getPrice()).divide(BigDecimal.valueOf(100));
            editSkuParam.setPrice(price);
            editSkuParam.setSellPrice(price);
            editSkuParam.setPriceMember(price);
        } else {
            editSkuParam.setPrice(mgtGoodsSkuInfoVo.getPrice());
            editSkuParam.setSellPrice(mgtGoodsSkuInfoVo.getSellPrice());
            editSkuParam.setPriceMember(mgtGoodsSkuInfoVo.getPriceMember());
        }
        editSkuParam.setSkuSpecList(mgtGoodsSkuInfoVo.getSkuSpecList());
        editSkuParam.setSkuAppear("0");
        editSkuParam.setBuyFactor("0");
        editSkuParam.setSkuValidity(DateUtil.Formatter.yyyyMMddHHmmss.format(mgtGoodsSkuInfoVo.getSkuValidity()));

        // 库存增量逻辑
        int newSqbTotal = (sqbSku != null && sqbSku.getQuantity() != null) ? sqbSku.getQuantity().intValue() : 0;
        int oldTotal = mgtGoodsSkuInfoVo.getStock() != null ? mgtGoodsSkuInfoVo.getStock() : 0;
        int operStock = newSqbTotal - oldTotal;

        if (operStock != 0) {
            int operStockVal = Math.abs(operStock);
            int currentRedisSurplus = goblinRedisUtils.getSkuStock(null, skuId);
            if (operStock < 0) {
                if (currentRedisSurplus >= operStockVal) {
                    if (goblinRedisUtils.decrSkuStock(null, skuId, operStockVal) >= 0) {
                        editSkuParam.setStock(oldTotal - operStockVal);
                        editSkuParam.setSkuStock(mgtGoodsSkuInfoVo.getSkuStock() - operStockVal);
                    }
                } else {
                    goblinRedisUtils.setSkuStock(null, skuId, newSqbTotal);
                    editSkuParam.setStock(newSqbTotal);
                    editSkuParam.setSkuStock(newSqbTotal);
                }
            } else {
                goblinRedisUtils.incrSkuStock(null, skuId, operStockVal);
                editSkuParam.setStock(oldTotal + operStockVal);
                editSkuParam.setSkuStock(mgtGoodsSkuInfoVo.getSkuStock() + operStockVal);
            }
        } else {
            editSkuParam.setStock(oldTotal);
            editSkuParam.setSkuStock(mgtGoodsSkuInfoVo.getSkuStock());
        }

        goblinstoreMgtGoodsService.goodsEditSku(currentUid, editSkuParam, mgtGoodsSkuInfoVo, mgtGoodsInfoVo, null, null);
    }

    private GoblinStoreMgtGoodsAddParam buildMgtGoodsAddParam(String storeId, MallProductsQueryData productsData) {
        GoblinStoreMgtGoodsAddParam param = new GoblinStoreMgtGoodsAddParam();
        param.setStoreId(storeId);
        param.setName(productsData.getTitle());
        param.setIntro(productsData.getProductIntroduction());
        param.setImageList(new ArrayList<>(productsData.getConverImages()));
        param.setDetails(productsData.getProductIntroduction());
        param.setSpecMode("1");
        param.setShelvesHandle("1");
        param.setVirtualFlg("1");

        List<GoblinStoreMgtGoodsAddSkuParam> skuParams = new ArrayList<>();
        List<MallProductsQueryData.Sku> sqbSkus = productsData.getSkuResults();
        if (CollectionUtils.isEmpty(sqbSkus)) {
            skuParams.add(buildMgtSkuParam(productsData.getTitle(), null, productsData.getConverImages()));
        } else {
            for (MallProductsQueryData.Sku sqbSku : sqbSkus) {
                skuParams.add(buildMgtSkuParam(null, sqbSku, productsData.getConverImages()));
            }
        }
        param.setSkuParamList(skuParams);
        return param;
    }

    private GoblinStoreMgtGoodsAddSkuParam buildMgtSkuParam(String defaultName, MallProductsQueryData.Sku sqbSku, List<String> images) {
        GoblinStoreMgtGoodsAddSkuParam sku = new GoblinStoreMgtGoodsAddSkuParam();
        sku.setSkuPic(!CollectionUtils.isEmpty(images) ? images.get(0) : "");
        sku.setSkuSpecList(new ArrayList<>());
        if (sqbSku != null) {
            BigDecimal price = BigDecimal.valueOf(sqbSku.getPrice()).divide(BigDecimal.valueOf(100));
            sku.setPrice(price);
            sku.setSellPrice(price);
            sku.setStock(sqbSku.getQuantity() != null ? sqbSku.getQuantity().intValue() : 0);
        } else {
            sku.setPrice(BigDecimal.ZERO);
            sku.setSellPrice(BigDecimal.ZERO);
            sku.setStock(0);
        }
        sku.setSkuValidity(DateUtil.Formatter.yyyyMMddHHmmss.format(LocalDateTime.now().plusYears(1)));
        sku.setSkuAppear("0");
        sku.setBuyFactor("0");
        return sku;
    }

    @Override
    public ResponseDto<List<GoblinSqbPerfGoodsVo>> getPerfGoods(String performancesId) {
        List<GoblinSqbPerfGoodsVo> cached = goblinSqbRedisUtils.getPerfGoods(performancesId);
        if (cached != null) return ResponseDto.success(cached);
        try {
            LambdaQueryWrapper<GoblinSqbPerformanceGoods> query = new LambdaQueryWrapper<>();
            query.eq(GoblinSqbPerformanceGoods::getPerformancesId, performancesId).eq(GoblinSqbPerformanceGoods::getStatus, 1).orderByAsc(GoblinSqbPerformanceGoods::getSort);
            List<GoblinSqbPerformanceGoods> relations = goblinSqbPerformanceGoodsMapper.selectList(query);
            if (CollectionUtils.isEmpty(relations)) {
                List<GoblinSqbPerfGoodsVo> empty = new ArrayList<>();
                goblinSqbRedisUtils.setPerfGoods(performancesId, empty);
                return ResponseDto.success(empty);
            }
            List<String> skuIds = relations.stream().map(GoblinSqbPerformanceGoods::getSkuId).collect(Collectors.toList());
            List<String> spuIds = relations.stream().map(GoblinSqbPerformanceGoods::getSpuId).distinct().collect(Collectors.toList());
            List<GoblinGoodsSku> skuList = goblinGoodsSkuMapper.selectList(new LambdaQueryWrapper<GoblinGoodsSku>().in(GoblinGoodsSku::getSkuId, skuIds));
            Map<String, GoblinGoodsSku> skuMap = skuList.stream().collect(Collectors.toMap(GoblinGoodsSku::getSkuId, Function.identity(), (a, b) -> a));
            List<GoblinGoods> spuList = goblinGoodsMapper.selectList(new LambdaQueryWrapper<GoblinGoods>().in(GoblinGoods::getSpuId, spuIds));
            Map<String, GoblinGoods> spuMap = spuList.stream().collect(Collectors.toMap(GoblinGoods::getSpuId, Function.identity(), (a, b) -> a));
            List<GoblinSqbPerfGoodsVo> result = new ArrayList<>();
            for (GoblinSqbPerformanceGoods rel : relations) {
                GoblinSqbPerfGoodsVo vo = new GoblinSqbPerfGoodsVo();
                vo.setSkuId(rel.getSkuId()); vo.setSpuId(rel.getSpuId()); vo.setSort(rel.getSort());
                GoblinGoodsSku sku = skuMap.get(rel.getSkuId());
                if (sku != null) { vo.setSkuName(sku.getName()); vo.setPrice(sku.getPrice() != null ? sku.getPrice().longValue() : null); }
                GoblinGoods spu = spuMap.get(rel.getSpuId());
                if (spu != null) { vo.setSpuName(spu.getName()); vo.setCoverPic(spu.getCoverPic()); }
                result.add(vo);
            }
            goblinSqbRedisUtils.setPerfGoods(performancesId, result);
            return ResponseDto.success(result);
        } catch (Exception e) {
            log.error("[收钱吧] getPerfGoods 异常", e);
            return ResponseDto.failure("查询失败");
        }
    }

    private CommonRequest.Seller buildSeller() {
        CommonRequest.Seller seller = new CommonRequest.Seller();
        seller.setMerchantId(SQB_MERCHANT_ID);
        seller.setMerchantUserId(SQB_MERCHANT_USER_ID);
        seller.setRole(SQB_ROLE);
        return seller;
    }

    private GoblinSqbGoodsExt buildExt(String spuId, String skuId, String mallSn, String sqbProductId, String sqbProductSn, String sqbSkuId, LocalDateTime now) {
        GoblinSqbGoodsExt ext = new GoblinSqbGoodsExt();
        ext.setSpuId(spuId); ext.setSkuId(skuId); ext.setMallSn(mallSn);
        ext.setSqbProductId(sqbProductId); ext.setSqbProductSn(sqbProductSn); ext.setSqbSkuId(sqbSkuId);
        ext.setCreatedAt(now); ext.setUpdatedAt(now);
        return ext;
    }
}
