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

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.liquidnet.common.exception.LiquidnetServiceException;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.goblin.dto.GoblinGoodsImportDto;
import com.liquidnet.service.goblin.dto.GoblinGoodsSpecDto;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsInfoVo;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsSkuInfoVo;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsSpecValueVo;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsSpecVo;
import com.liquidnet.service.goblin.util.GoblinMongoUtils;
import com.liquidnet.service.goblin.util.GoblinRedisUtils;
import com.liquidnet.service.goblin.util.ObjectUtil;
import com.liquidnet.service.goblin.util.QueueUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Pattern;

@Slf4j
@Service
public class GoblinStoreMgtGoodsImportService {
    @Autowired
    QueueUtils queueUtils;
    @Autowired
    GoblinRedisUtils goblinRedisUtils;
    @Autowired
    GoblinMongoUtils goblinMongoUtils;

    /**
     * 大小字母 || 数字
     * 长度：0,50
     */
    public static final String ALPHABET_NUMBER_UNDER_50 = "^[a-zA-Z0-9]{0,50}$";

    /**
     * 大小字母 || 数字
     * 长度：0,32
     */
    public static final String ALPHABET_NUMBER_32 = "^[a-zA-Z0-9]{0,32}$";

    private void goodsInformationDataAnalysisProcessingValid(GoblinGoodsImportDto dto, List<String> skuBarCodeTmpList, Integer rowNum) {
        /* 商品编码校验｜------------------------------------------------------------------------------ */
        if (StringUtils.isNotEmpty(dto.getSpuCode()) && !Pattern.matches(ALPHABET_NUMBER_UNDER_50, dto.getSpuCode())) {
            throw new LiquidnetServiceException("-1", String.format("数据内容不规范【第%s行商品编码有误】", rowNum));
        }
        /* 商品名称校验｜------------------------------------------------------------------------------ */
        if (StringUtils.isEmpty(dto.getSpuName()) || dto.getSpuName().length() > 100) {
            throw new LiquidnetServiceException("-1", String.format("数据内容不规范【第%s行商品名称有误】", rowNum));
        }
        /* 商品图片校验｜------------------------------------------------------------------------------ */
        if (StringUtils.isNotEmpty(dto.getSpuImgs())) {
            if (dto.getSpuImgs().startsWith("【图片链接】")) {
                String[] spuImgsArr = dto.getSpuImgs().replace("【图片链接】", "").replace(";", "；").split("；");
                if (spuImgsArr.length > 15) {
                    throw new LiquidnetServiceException("-1", String.format("数据内容不规范【第%s行商品图片最多支持15张】", rowNum));
                }
                ArrayList<String> spuImgList = CollectionUtil.arrayListString();
                for (String spuImg : spuImgsArr) {
                    if (StringUtils.isNotBlank(spuImg)) {
                        spuImgList.add(spuImg);
                    }
                }
                if (!CollectionUtils.isEmpty(spuImgList)) {
                    dto.setSpuImgList(spuImgList);
                }
            } else {
                throw new LiquidnetServiceException("-1", String.format("数据内容不规范【第%s行商品图片格式有误】", rowNum));
            }
        }
        /* 商品规格校验｜------------------------------------------------------------------------------ */
        if (StringUtils.isEmpty(dto.getSkuSpec())) {
            throw new LiquidnetServiceException("-1", String.format("数据内容不规范【第%s行商品规格信息缺失】", rowNum));
        }
        String[] skuSpecArr = dto.getSkuSpec().replace(":", "：").replace(";", "；").split("；");
        List<GoblinGoodsSpecDto> skuSpecDtos = ObjectUtil.getGoblinGoodsSpecDtoArrayList();
        for (int i = 0, size = skuSpecArr.length; i < size; i++) {
            String skuSpec = skuSpecArr[i];
            if (StringUtils.isEmpty(skuSpec)) {
                throw new LiquidnetServiceException("-1", String.format("数据内容不规范【第%s行商品规格信息有误】", rowNum));
            }
            String[] specArr = skuSpec.split("：");
            if (ArrayUtils.isEmpty(specArr) || specArr.length != 2
                    || specArr[0].length() > 5 || specArr[1].length() > 40
            ) {
                throw new LiquidnetServiceException("-1", String.format("数据内容不规范【第%s行商品规格信息有误】", rowNum));
            }

            GoblinGoodsSpecDto skuSpecDto = GoblinGoodsSpecDto.getNew();
            skuSpecDto.setSpecName(specArr[0]);
            skuSpecDto.setSpecVname(specArr[1]);
            skuSpecDtos.add(skuSpecDto);
            dto.setSkuSpecDtos(skuSpecDtos);
        }
        /* 规格编码校验｜------------------------------------------------------------------------------ */
        if (StringUtils.isNotEmpty(dto.getSkuCode()) && !Pattern.matches(ALPHABET_NUMBER_UNDER_50, dto.getSkuCode())) {
            throw new LiquidnetServiceException("-1", String.format("数据内容不规范【第%s行规格编码格式有误】", rowNum));
        }
        /* 价格校验｜------------------------------------------------------------------------------ */
        if (null == dto.getPrice() || dto.getPrice().compareTo(BigDecimal.valueOf(0.01)) < 0 || dto.getPrice().compareTo(BigDecimal.valueOf(9999999)) > 0) {
            throw new LiquidnetServiceException("-1", String.format("数据内容不规范【第%s行价格信息有误】", rowNum));
        }
        /* 库存校验｜------------------------------------------------------------------------------ */
        if (null == dto.getStock() || dto.getStock() < 0 || dto.getStock() > 9999999) {// 数据不规范停止解析并提示用户
            throw new LiquidnetServiceException("-1", String.format("数据内容不规范【第%s行库存信息有误】", rowNum));
        }
        /* 规格图片校验｜------------------------------------------------------------------------------ */
        if (StringUtils.isNotEmpty(dto.getSkuImg())) {
            if (dto.getSkuImg().startsWith("【图片链接】")) {
                String[] skuImgArr = dto.getSkuImg().replace("【图片链接】", "").replace(";", "；").split("；");
                if (skuImgArr.length == 1) {
                    dto.setSkuImg(StringUtils.isNotBlank(skuImgArr[0]) ? skuImgArr[0] : null);
                } else {
                    throw new LiquidnetServiceException("-1", String.format("数据内容不规范【第%s行规格图片仅支持1张】", rowNum));
                }
            } else {
                throw new LiquidnetServiceException("-1", String.format("数据内容不规范【第%s行规格图片格式有误】", rowNum));
            }
        }
        /* 规格条码校验｜------------------------------------------------------------------------------ */
        if (StringUtils.isNotEmpty(dto.getSkuBarCode())) {
            if (Pattern.matches(ALPHABET_NUMBER_32, dto.getSkuBarCode())) {
                if (skuBarCodeTmpList.contains(dto.getSkuBarCode())) {
                    throw new LiquidnetServiceException("-1", String.format("数据内容不规范【第%s行表格内规格条码重复】", rowNum));
                }
                skuBarCodeTmpList.add(dto.getSkuBarCode());
            } else {
                throw new LiquidnetServiceException("-1", String.format("数据内容不规范【第%s行规格条码格式有误】", rowNum));
            }
        }
        /* 校验｜------------------------------------------------------------------------------ */
        /* 校验｜------------------------------------------------------------------------------ */
        /* 校验｜------------------------------------------------------------------------------ */
    }

    public void goodsInformationDataAnalysisProcessing(MultipartFile file, String uid, String storeId) throws IOException {
        List<String> skuBarCodeTmpList = CollectionUtil.arrayListString();
        List<GoblinGoodsInfoVo> goodsInfoVos = ObjectUtil.goblinGoodsInfoVoArrayList();
        List<GoblinGoodsSkuInfoVo> goodsSkuInfoVos = ObjectUtil.getGoblinGoodsSkuInfoVoArrayList();
        LinkedList<Object[]> initGoodsSkuObjs = CollectionUtil.linkedListObjectArr();

        EasyExcel.read(file.getInputStream(), GoblinGoodsImportDto.class, new AnalysisEventListener<GoblinGoodsImportDto>() {

                    @Override
                    public void onException(Exception exception, AnalysisContext context) throws Exception {
                        if (exception instanceof ExcelDataConvertException) {
                            Integer rowIndex = ((ExcelDataConvertException) exception).getRowIndex();
                            Integer columnIndex = ((ExcelDataConvertException) exception).getColumnIndex();
                            throw new LiquidnetServiceException("-1", String.format("数据内容不规范【第%s行，第%s列数据格式有误】", rowIndex + 1, columnIndex + 1));
                        }
                        super.onException(exception, context);
                    }

                    @Override
                    public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
                        Integer approximateTotalRowNumber = context.readSheetHolder().getApproximateTotalRowNumber();
                        if (approximateTotalRowNumber > 501) {
                            log.warn("店铺商品管理:批量导入数据:异常[UID={},storeId={},totalRowNumber={}]", uid, storeId, approximateTotalRowNumber);
                            throw new LiquidnetServiceException("-1", "超出总行数限制500");
                        }
                        super.invokeHead(headMap, context);
                    }

                    @Override
                    public void invoke(GoblinGoodsImportDto dto, AnalysisContext analysisContext) {
                        Integer rowIndex = analysisContext.readRowHolder().getRowIndex();

                        goodsInformationDataAnalysisProcessingValid(dto, skuBarCodeTmpList, rowIndex + 1);

                        GoblinGoodsInfoVo lastGoodsInfoVo = CollectionUtils.isEmpty(goodsInfoVos) ? null : goodsInfoVos.get(goodsInfoVos.size() - 1);
                        GoblinGoodsInfoVo goodsInfoVo = goodsInformationDataAnalysisProcessingForSpu(dto, lastGoodsInfoVo, uid, storeId,
                                LocalDateTime.now(), goodsSkuInfoVos, initGoodsSkuObjs);

                        if (null != goodsInfoVo) {
                            log.debug("dt2:{}", goodsInfoVo);
                            goodsInfoVos.add(goodsInfoVo);
                        }
                    }

                    @Override
                    public void doAfterAllAnalysed(AnalysisContext analysisContext) {// 解析完成...
                        log.debug("dt3-1:{}", JsonUtils.toJson(goodsInfoVos));
                        log.debug("dt3-2:{}", JsonUtils.toJson(goodsSkuInfoVos));

                        List<String> existGoodsSkuNoList = goblinMongoUtils.existGoodsSkuNoBySkuNoList(storeId, skuBarCodeTmpList);
                        if (!CollectionUtils.isEmpty(existGoodsSkuNoList)) {
                            if (existGoodsSkuNoList.size() > 3) {
                                throw new LiquidnetServiceException("-1", String.format("规格条码与已添加商品条码重复，重复条码如下：   %s,...", StringUtils.join(existGoodsSkuNoList.subList(0, 3), ",")));
                            }
                            throw new LiquidnetServiceException("-1", String.format("规格条码与已添加商品条码重复，重复条码如下：   %s", StringUtils.join(existGoodsSkuNoList, ",")));
                        }

//                        goblinMongoUtils.insertMgtGoodsInfoVos(goodsInfoVos);
//                        goblinMongoUtils.insertMgtGoodsSkuInfoVos(goodsSkuInfoVos);
//                        goodsSkuInfoVos.forEach(r -> goblinRedisUtils.setSkuStock(null, r.getSkuId(), r.getSkuStock()));
//
//                        LinkedList<String> toMqSqls = CollectionUtil.linkedListString();
//                        toMqSqls.add(SqlMapping.get("goblin_goods.insert"));
//                        LinkedList<Object[]> initGoodsObjs = CollectionUtil.linkedListObjectArr();
//                        goodsInfoVos.forEach(r -> initGoodsObjs.add(new Object[]{
//                                r.getSpuId(), r.getSpuNo(), r.getName(), r.getSubtitle(), r.getSellPrice(),
//                                r.getPriceGe(), r.getPriceLe(), r.getIntro(), r.getDetails(), r.getCoverPic(),
//                                r.getVideo(), r.getSpecMode(), r.getStoreId(), r.getCateFid(), r.getCateSid(),
//                                r.getCateTid(), r.getStoreCateFid(), r.getStoreCateSid(), r.getStoreCateTid(), r.getBrandId(),
//                                r.getShelvesHandle(), r.getShelvesTime(), r.getSpuValidity(), r.getVirtualFlg(), r.getStatus(),
//                                r.getShelvesStatus(), r.getSpuAppear(), r.getShelvesAt(), r.getCreatedBy(), r.getCreatedAt(),
//                                r.getLogisticsTemplate()
//                        }));
//                        toMqSqls.add(SqlMapping.get("goblin_goods_sku.insert"));
//                        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.SQL_GOODS.getKey(), SqlMapping.gets(toMqSqls, initGoodsObjs, initGoodsSkuObjs));
                    }
                }
        ).sheet(0).doReadSync();
    }

    private GoblinGoodsInfoVo goodsInformationDataAnalysisProcessingForSpu(GoblinGoodsImportDto dt,GoblinGoodsInfoVo lastGoodsInfoVo,
                                                                           String uid, String storeId, LocalDateTime now,
                                                                           List<GoblinGoodsSkuInfoVo> goodsSkuInfoVos, LinkedList<Object[]> initGoodsSkuObjs) {
        log.debug("dt1:{}", dt.toString());

        boolean tobeNextSpuFlg = false;
        if (null == lastGoodsInfoVo || !lastGoodsInfoVo.getName().equals(dt.getSpuName())) {
            lastGoodsInfoVo = GoblinGoodsInfoVo.getNew();
            tobeNextSpuFlg = true;
        }
        if (tobeNextSpuFlg) {
            lastGoodsInfoVo.setName(dt.getSpuName());//*
            if (StringUtils.isNotEmpty(dt.getSpuCode())) {
                lastGoodsInfoVo.setSpuId(IDGenerator.nextMilliId2() + dt.getSpuCode());//*
            } else {
                lastGoodsInfoVo.setSpuId(IDGenerator.nextMilliId2());//*
            }
//            if (StringUtils.isNotEmpty(dt.getSpuBarCode())) {
//                lastGoodsInfoVo.setSpuNo(dt.getSpuBarCode());//*
//            } else {
                lastGoodsInfoVo.setSpuNo(lastGoodsInfoVo.getSpuId());//*
//            }
            if (!CollectionUtils.isEmpty(dt.getSpuImgList())) {
                lastGoodsInfoVo.setImageList(dt.getSpuImgList());
                lastGoodsInfoVo.setCoverPic(lastGoodsInfoVo.getImageList().get(0));
            }

            lastGoodsInfoVo.setDetails(lastGoodsInfoVo.getName());
            lastGoodsInfoVo.setSpuType(0);//*
            lastGoodsInfoVo.setSpecMode("1");//*
            lastGoodsInfoVo.setShelvesHandle("1");
            lastGoodsInfoVo.setVirtualFlg("0");
            lastGoodsInfoVo.setStatus("3");
            lastGoodsInfoVo.setShelvesStatus("0");
            lastGoodsInfoVo.setSpuAppear("0");//*
            lastGoodsInfoVo.setSpuCanbuy("1");
            lastGoodsInfoVo.setDelFlg("0");
            lastGoodsInfoVo.setCreatedAt(now);
            lastGoodsInfoVo.setCreatedBy(uid);//*
            lastGoodsInfoVo.setStoreId(storeId);//*
        }
        GoblinGoodsSkuInfoVo lastGoodsSkuInfoVo = this.goodsInformationDataAnalysisProcessingForSku(dt, lastGoodsInfoVo, uid, storeId, now, tobeNextSpuFlg);
        if (null != lastGoodsSkuInfoVo) {
            goodsSkuInfoVos.add(lastGoodsSkuInfoVo);
            initGoodsSkuObjs.add(new Object[]{
                    lastGoodsSkuInfoVo.getSkuId(), lastGoodsSkuInfoVo.getSpuId(), lastGoodsSkuInfoVo.getSkuNo(), lastGoodsSkuInfoVo.getName(), lastGoodsSkuInfoVo.getSubtitle(),
                    lastGoodsSkuInfoVo.getSellPrice(), lastGoodsSkuInfoVo.getSkuPic(), lastGoodsSkuInfoVo.getSkuIsbn(), lastGoodsSkuInfoVo.getStock(), lastGoodsSkuInfoVo.getSkuStock(),
                    lastGoodsSkuInfoVo.getWarningStock(), lastGoodsSkuInfoVo.getPrice(), lastGoodsSkuInfoVo.getPriceMember(), lastGoodsSkuInfoVo.getWeight(), lastGoodsSkuInfoVo.getBuyFactor(),
                    lastGoodsSkuInfoVo.getBuyRoster(), lastGoodsSkuInfoVo.getBuyLimit(), lastGoodsSkuInfoVo.getStoreId(), lastGoodsSkuInfoVo.getSkuValidity(), lastGoodsSkuInfoVo.getVirtualFlg(),
                    lastGoodsSkuInfoVo.getStatus(), lastGoodsSkuInfoVo.getShelvesStatus(), lastGoodsSkuInfoVo.getSkuAppear(), lastGoodsSkuInfoVo.getShelvesAt(), uid,
                    now, lastGoodsSkuInfoVo.getLogisticsTemplate()
            });
        }
        return tobeNextSpuFlg ? lastGoodsInfoVo : null;
    }

    private GoblinGoodsSkuInfoVo goodsInformationDataAnalysisProcessingForSku(GoblinGoodsImportDto dt, GoblinGoodsInfoVo lastGoodsInfoVo,
                                                              String uid, String storeId, LocalDateTime now, boolean tobeNextSpuFlg) {
        GoblinGoodsSkuInfoVo skuInfoVo = GoblinGoodsSkuInfoVo.getNew();

        skuInfoVo.setName("");
        List<GoblinGoodsSpecDto> skuSpecDtos = dt.getSkuSpecDtos();
        List<GoblinGoodsSpecVo> spuSpecVos = tobeNextSpuFlg ? ObjectUtil.getGoblinGoodsSpecVoArrayList() : lastGoodsInfoVo.getSpecVoList();
        for (int i = 0, size = skuSpecDtos.size(); i < size; i++) {
            GoblinGoodsSpecDto skuSpecDto = skuSpecDtos.get(i);

            skuInfoVo.setName(skuInfoVo.getName().concat(skuSpecDto.getSpecVname()));

            if (tobeNextSpuFlg) {
                List<GoblinGoodsSpecValueVo> spuSpecValueVos = ObjectUtil.getGoblinGoodsSpecValueVoArrayList();
                spuSpecValueVos.add(GoblinGoodsSpecValueVo.getNew().setSpecVname(skuSpecDto.getSpecVname()).setSpecVsort(1));
                GoblinGoodsSpecVo spuSpecVo = GoblinGoodsSpecVo.getNew().setSpecName(skuSpecDto.getSpecName()).setSpecSort(i + 1).setSpecValues(spuSpecValueVos);
                spuSpecVos.add(spuSpecVo);
            } else {
                Optional<GoblinGoodsSpecVo> hasSpecOptional = spuSpecVos.stream().filter(r -> r.getSpecName().equals(skuSpecDto.getSpecName())).findAny();
                if (hasSpecOptional.isPresent()) {
                    GoblinGoodsSpecVo spuSpecVo = hasSpecOptional.get();

                    List<GoblinGoodsSpecValueVo> spuSpecValueVos = spuSpecVo.getSpecValues();
                    Optional<GoblinGoodsSpecValueVo> any = spuSpecValueVos.stream().filter(r -> r.getSpecVname().equals(skuSpecDto.getSpecVname())).findAny();
                    if (!any.isPresent()) {
                        spuSpecValueVos.add(
                                GoblinGoodsSpecValueVo.getNew().setSpecVname(skuSpecDto.getSpecVname()).setSpecVsort(lastGoodsInfoVo.getSkuIdList().size() + 1)
                        );
                        spuSpecVo.setSpecValues(spuSpecValueVos);
                    }
                } else {// 不匹配的规格直接跳过（默认只匹配商品第一行数据中的规格项）
                    return null;
                }
            }
        }

        skuInfoVo.setStock(dt.getStock());//*
        skuInfoVo.setSkuStock(dt.getStock());//*
        skuInfoVo.setPrice(dt.getPrice());//*
        skuInfoVo.setPriceMember(dt.getPrice());//*
        if (StringUtils.isNotEmpty(dt.getSkuCode())) {
            skuInfoVo.setSkuId(lastGoodsInfoVo.getSpuId().concat(dt.getSkuCode()).concat(StringUtils.right(String.valueOf(System.nanoTime()), 5)));//*
        } else {
            skuInfoVo.setSkuId(lastGoodsInfoVo.getSpuId().concat(StringUtils.right(String.valueOf(System.nanoTime()), 5)));//*
        }
        if (StringUtils.isNotEmpty(dt.getSkuImg())) {
            skuInfoVo.setSkuPic(dt.getSkuImg());
        } else {
//            skuInfoVo.setSkuPic("");// 设置默认图片
        }
        if (StringUtils.isNotEmpty(dt.getSkuBarCode())) {
            skuInfoVo.setSkuNo(dt.getSkuBarCode());//*
        } else {
            skuInfoVo.setSkuNo(lastGoodsInfoVo.getSpuNo());//*
        }

        skuInfoVo.setSpuId(lastGoodsInfoVo.getSpuId());//*
        skuInfoVo.setSkuType(0);//*
        skuInfoVo.setBuyFactor("0");
        skuInfoVo.setBuyLimit(0);
        skuInfoVo.setStatus("3");
        skuInfoVo.setShelvesStatus(lastGoodsInfoVo.getShelvesStatus());
        skuInfoVo.setSoldoutStatus("0");//*
        skuInfoVo.setSkuAppear("0");//*
        skuInfoVo.setSkuCanbuy("1");
        skuInfoVo.setDelFlg("0");
        skuInfoVo.setCreatedAt(now);//*
        skuInfoVo.setCreatedBy(uid);//*
        skuInfoVo.setStoreId(storeId);
        skuInfoVo.setSkuSpecList(skuSpecDtos);

        if (tobeNextSpuFlg) {
            List<String> skuIdList = CollectionUtil.arrayListString();
            skuIdList.add(skuInfoVo.getSkuId());
            lastGoodsInfoVo.setSkuIdList(skuIdList);
            lastGoodsInfoVo.setSpecVoList(spuSpecVos);
            lastGoodsInfoVo.setPriceGe(skuInfoVo.getPrice());
            lastGoodsInfoVo.setPriceLe(skuInfoVo.getPrice());
        } else {
            BigDecimal priceGe = lastGoodsInfoVo.getPriceGe();
            BigDecimal priceLe = lastGoodsInfoVo.getPriceLe();
            List<String> skuIdList = lastGoodsInfoVo.getSkuIdList();

            skuIdList.add(skuInfoVo.getSkuId());

            lastGoodsInfoVo.setSkuIdList(skuIdList);
            lastGoodsInfoVo.setSpecVoList(spuSpecVos);
            lastGoodsInfoVo.setPriceGe(skuInfoVo.getPrice().compareTo(priceGe) < 0 ? skuInfoVo.getPrice() : priceGe);
            lastGoodsInfoVo.setPriceLe(priceLe.compareTo(skuInfoVo.getPrice()) < 0 ? skuInfoVo.getPrice() : priceLe);
        }
        return skuInfoVo;
    }
}
