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

import com.alibaba.fastjson.JSON;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.erp.config.ErpWdtClient;
import com.liquidnet.service.erp.constant.ErpEnum;
import com.liquidnet.service.erp.param.LogisticsListParam;
import com.liquidnet.service.erp.param.OrderListParam;
import com.liquidnet.service.erp.param.TradeListParam;
import com.liquidnet.service.erp.utils.ErpObjectUtil;
import com.liquidnet.service.erp.vo.*;
import com.liquidnet.service.goblin.constant.GoblinRedisConst;
import com.liquidnet.service.goblin.constant.GoblinStatusConst;
import com.liquidnet.service.goblin.dto.vo.*;
import com.liquidnet.service.goblin.service.IGoblinErpService;
import com.liquidnet.service.goblin.service.manage.IGoblinStoreOrderService;
import com.liquidnet.service.goblin.util.GoblinRedisUtils;
import com.liquidnet.service.goblin.util.ObjectUtil;
import com.liquidnet.service.goblin.util.QueueUtils;
import com.mongodb.BasicDBObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * <p>
 * 支付订单表 服务实现类
 * </p>
 *
 * @author liquidnet
 * @since 2021-07-20
 */
@Service
@Slf4j
public class WdtServiceImpl implements IGoblinErpService {

    @Autowired
    ErpWdtClient erpWdtClient;
    @Autowired
    GoblinRedisUtils goblinRedisUtils;
    @Autowired
    MongoTemplate mongoTemplate;
    @Autowired
    MongoConverter mongoConverter;
    @Autowired
    IGoblinStoreOrderService goblinStoreOrderService;
    @Autowired
    QueueUtils queueUtils;
    @Value("${liquidnet.erp.wdt.redisSize}")
    private int redisSize;
    @Value("${liquidnet.erp.wdt.store.shop_no}")
    private String shopNo;
    @Value("${liquidnet.erp.wdt.contentSize}")
    private int contentSize;

    @Override
    public ResponseDto<Boolean> initErpStock(String spuId, int min) {
        try {
            Date nowTime = DateUtil.now();
            String json;
            Map<String, String> param = CollectionUtil.linkMapStringString();
            param.put("start_time", DateUtil.format(DateUtil.addMin(nowTime, -min), DateUtil.Formatter.yyyyMMddHHmmss));
            param.put("end_time", DateUtil.format(nowTime, DateUtil.Formatter.yyyyMMddHHmmss));
            if (null != spuId && !"".equals(spuId)) {
                //查询 spu下的sku
                GoblinGoodsInfoVo goblinGoodsInfoVo = goblinRedisUtils.getGoodsInfoVo(spuId);
                for (String skuId : goblinGoodsInfoVo.getSkuIdList()) {
                    GoblinGoodsSkuInfoVo skuInfoVo = goblinRedisUtils.getGoodsSkuInfoVo(skuId);
                    if (skuInfoVo.getErpHosting() == 1) {
                        param.put("warehouse_no", skuInfoVo.getErpWarehouseNo());
                        param.put("spec_no", skuInfoVo.getSkuErpCode());
                        json = erpWdtClient.execute(ErpEnum.WdtAPI.STOCK_QUERY.getUri(), param);
                        ArrayList<SyncStockVo> list = baseStock(json);
                        syncStock(list);
                    }
                }
            } else {
                int pageSize = 40;
                int allCount = (int) mongoTemplate.count(Query.query(Criteria.where("erpHosting").is(1)
//                        .and("skuType").is("0")
                ), GoblinGoodsSkuInfoVo.class, GoblinGoodsSkuInfoVo.class.getSimpleName());//总条数
                int pageCount = (allCount / pageSize) + 1;
                param.put("page_size", pageSize + "");
                for (int i = 0; i < pageCount; i++) {
                    param.put("page_no", i + "");
                    json = erpWdtClient.execute(ErpEnum.WdtAPI.STOCK_QUERY.getUri(), param);
                    ArrayList<SyncStockVo> list = baseStock(json);
                    syncStock(list);
                }
            }
        } catch (Exception e) {
            log.error("调用接口失败 spuId:{},min:{}", spuId, min);
            return ResponseDto.failure();
        }
        return ResponseDto.success();
    }

    private ArrayList<SyncStockVo> baseStock(String json) {
        ArrayList<SyncStockVo> stockMap = ErpObjectUtil.syncStockVoList();
        try {
            StockQueryBaseVo data = JsonUtils.fromJson(json, StockQueryBaseVo.class);
            List<StockQueryVo> stockQueryVos = data.getStocks();
            for (StockQueryVo stockQueryVo : stockQueryVos) {
                try {
                    BigDecimal stockNum = stockQueryVo.getStock_num();//可发库存
                    SyncStockVo vo = SyncStockVo.getNew();
                    vo.setSpecNo(stockQueryVo.getSpec_no());
                    vo.setStockErpNum(stockNum);
                    vo.setWarehouseNo(stockQueryVo.getWarehouse_no());
                    stockMap.add(vo);
                } catch (Exception e) {
                    log.error("解析erp数据失败 内层：{}", stockQueryVo);
                }

            }
        } catch (Exception e) {
            log.error("解析erp数据失败 外层：{}", json);
        }
        return stockMap;
    }

    //同步库存
    private void syncStock(ArrayList<SyncStockVo> stockMap) {
        for (SyncStockVo vo : stockMap) {
            String skuId = "";
            try {
                GoblinGoodsSkuInfoVo skuInfoVo = mongoTemplate.findOne(Query.query(Criteria.where("skuErpCode").is(vo.getSpecNo()).and("erpWarehouseNo").is(vo.getWarehouseNo())), GoblinGoodsSkuInfoVo.class, GoblinGoodsSkuInfoVo.class.getSimpleName());
                int changeStock = vo.getStockErpNum().subtract(BigDecimal.valueOf(skuInfoVo.getSkuStock())).intValue();
                skuId = skuInfoVo.getSkuId();
                //mongo修改
                HashMap<String, Object> map = new HashMap<>();
                map.put("stock", vo.getStockErpNum().intValue());
                map.put("skuStock", vo.getStockErpNum().intValue());
                BasicDBObject obj = new BasicDBObject("$set", mongoConverter.convertToMongoType(map));
                mongoTemplate.getCollection(GoblinGoodsSkuInfoVo.class.getSimpleName()).updateOne(
                        Query.query(Criteria.where("skuId").is(skuId)).getQueryObject(),
                        obj);
                goblinRedisUtils.del(GoblinRedisConst.BASIC_GOODS_SKU.concat(skuId));
                //sql 当前库存 增加changeStock
                queueUtils.sendMsgByRedis(MQConst.GoblinQueue.GOBLIN_ORDER_CLOSE.getKey(),
                        SqlMapping.get("goblin_sku.stock", vo.getStockErpNum().intValue(), vo.getStockErpNum().intValue(), LocalDateTime.now(), vo.getSpecNo(), vo.getWarehouseNo()));
                //redis incr 增加changeStock
                int stock = 0;
                if (changeStock > 0) {
                    stock = goblinRedisUtils.incrSkuStock(null, skuId, changeStock);
                } else if (changeStock < 0) {
                    stock = goblinRedisUtils.decrSkuStock(null, skuId, Math.abs(changeStock));
                }
                log.info("skuId:{},库存:{}", skuId, stock);
            } catch (Exception e) {
                e.printStackTrace();
                log.error("同步库存失败 skuId:{},erpSpecNo:{},warehouseNo:{}", skuId, vo.getSpecNo(), vo.getWarehouseNo());
            }
        }
    }


    @Override
    public ResponseDto<Boolean> pushTrade(String singleId) {
        List<TradeListParam> listOrder = ErpObjectUtil.tradeListParam();
        List<List<String>> orderIdList = CollectionUtil.arrayListListString();
        // 获取 订单id 数据
        if ("".equals(singleId) || null == singleId) {
//            for (int i = 0; i < redisSize; i++) {
//                List<String> list = goblinRedisUtils.getRange(i);
//                orderIdList.add(list);
//                //todo 删除redis key
//            }

            List<String> list = CollectionUtil.arrayListString();
            for (int i = 0; i < contentSize; i++) {
                String orderId = goblinRedisUtils.erpLeftPop(i);
                list.add(orderId);
            }
            orderIdList.add(list);
        } else {
            List<String> a = CollectionUtil.arrayListString();
            a.add(singleId);
            orderIdList.add(a);
        }

        //同步订单
        for (List<String> b : orderIdList) {
            for (String orderId : b) {
                goblinOrderData(orderId, listOrder);
                nftOrderData(orderId, listOrder);
            }
            //执行同步订单
            Map<String, String> param = CollectionUtil.linkMapStringString();
            param.put("shop_no", shopNo);
            param.put("trade_list", JSON.toJSONString(listOrder));
            String json = erpWdtClient.execute(ErpEnum.WdtAPI.TRADE_PUSH.getUri(), param);
            TradePushVo data = JsonUtils.fromJson(json, TradePushVo.class);
            int newCount = data.getNew_count();
            if (listOrder.size() < newCount) {
                log.error("同步 erp 失败 ");
            }
        }
        return ResponseDto.success();
    }

    //构建 商品订单数据
    private List<TradeListParam> goblinOrderData(String orderId, List<TradeListParam> listOrder) {
        TradeListParam tradeListParam = TradeListParam.getNew();
        GoblinStoreOrderVo orderVo = goblinRedisUtils.getGoblinOrder(orderId);
        if (orderVo == null) {
            return listOrder;
        }
        List<String> orderSkuIds = orderVo.getOrderSkuVoIds();
        List<OrderListParam> listOrderSku = ErpObjectUtil.orderListParam();
        String warehouseNo = "";
        int erpHosting = 0;
        //配置sku维度数据
        for (String orderSkuId : orderSkuIds) {
            OrderListParam orderSkuParam = OrderListParam.getNew();
            GoblinOrderSkuVo orderSkuVo = goblinRedisUtils.getGoblinOrderSkuVo(orderSkuId);
            if (orderSkuVo.getErpHosting() == 1 && orderSkuVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_2.getValue()) {
                erpHosting = 1;
            } else {
                continue;
            }
            orderSkuParam.setOid(orderSkuVo.getOrderSkuId());
            orderSkuParam.setNum(BigDecimal.valueOf(orderSkuVo.getNum()));
            orderSkuParam.setPrice(orderSkuVo.getSkuPrice());
            orderSkuParam.setStatus(ErpEnum.WdtStatus.STATUS_UN_SEND.WdtStatus());
            orderSkuParam.setRefund_status(0);
            orderSkuParam.setGoods_id(orderSkuVo.getSpuId());
            orderSkuParam.setSpec_id(orderSkuVo.getSkuId());
            orderSkuParam.setGoods_no(orderSkuVo.getSpuErpCode());
            orderSkuParam.setSpec_no(orderSkuVo.getSkuErpCode());
            orderSkuParam.setGoods_name(orderSkuVo.getSpuName());
            orderSkuParam.setAdjust_amount(BigDecimal.ZERO);
            orderSkuParam.setDiscount(BigDecimal.ZERO);
            orderSkuParam.setShare_discount(orderSkuVo.getPriceVoucher());
            warehouseNo = orderSkuVo.getErpWarehouseNo();
            listOrderSku.add(orderSkuParam);
        }
        //配置订单维度数据
        tradeListParam.setOrder_list(listOrderSku);
        tradeListParam.setTid(orderVo.getOrderCode());
        tradeListParam.setTrade_status(ErpEnum.WdtStatus.STATUS_UN_SEND.WdtStatus());
        tradeListParam.setPay_status(2);
        tradeListParam.setDelivery_term(1);
        tradeListParam.setTrade_time(orderVo.getCreatedAt());
        tradeListParam.setPay_time(orderVo.getPayTime());
        tradeListParam.setBuyer_nick(orderVo.getUserName());
        tradeListParam.setPay_id(orderVo.getPayCode());
        if (orderVo.getOrderAttrVo().getExpressAddress().equals("")) {
            tradeListParam.setReceiver_name("正在映画");
            tradeListParam.setReceiver_province("北京市");
            tradeListParam.setReceiver_city("北京市");
            tradeListParam.setReceiver_district("朝阳区");
            tradeListParam.setReceiver_address("广渠路 创1985园区  3-12");
            tradeListParam.setReceiver_mobile("15901093014");
        } else {
            tradeListParam.setReceiver_name(orderVo.getOrderAttrVo().getExpressContacts());
            String[] address = orderVo.getOrderAttrVo().getExpressAddress().split(" ");
            if (address.length > 0) {
                tradeListParam.setReceiver_province(address[0]);
            }
            if (address.length > 1) {
                tradeListParam.setReceiver_city(address[1]);
            }
            if (address.length > 2) {
                tradeListParam.setReceiver_district(address[2]);
            }
            tradeListParam.setReceiver_address(orderVo.getOrderAttrVo().getExpressAddress());
            tradeListParam.setReceiver_mobile(orderVo.getOrderAttrVo().getExpressPhone());
        }
        tradeListParam.setPost_amount(orderVo.getPriceExpress());
        tradeListParam.setExt_cod_fee(BigDecimal.ZERO);
        tradeListParam.setOther_amount(BigDecimal.ZERO);
        tradeListParam.setPaid(orderVo.getPriceActual());
        tradeListParam.setWarehouse_no(warehouseNo);
        if (erpHosting == 1) {
            listOrder.add(tradeListParam);
        }
        return listOrder;
    }

    //构建 nft订单数据
    private List<TradeListParam> nftOrderData(String orderId, List<TradeListParam> listOrder) {
        TradeListParam tradeListParam = TradeListParam.getNew();
        GoblinNftOrderVo orderVo = goblinRedisUtils.getGoblinNftOrder(orderId);
        List<OrderListParam> listOrderSku = ErpObjectUtil.orderListParam();
        //配置sku维度数据
        OrderListParam orderSkuParam = OrderListParam.getNew();
        if (orderVo != null && orderVo.getErpHosting() == 1 && orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_2.getValue()) {
            GoblinGoodsSkuInfoVo skuVo = goblinRedisUtils.getGoodsSkuInfoVo(orderVo.getSkuId());
            GoblinGoodsInfoVo spuVo = goblinRedisUtils.getGoodsInfoVo(orderVo.getSpuId());
            orderSkuParam.setOid(orderVo.getOrderId().concat("a1"));
            orderSkuParam.setNum(BigDecimal.valueOf(orderVo.getNum()));
            orderSkuParam.setPrice(skuVo.getPrice());
            orderSkuParam.setStatus(ErpEnum.WdtStatus.STATUS_UN_SEND.WdtStatus());
            orderSkuParam.setRefund_status(0);
            orderSkuParam.setGoods_id(orderVo.getSpuId());
            orderSkuParam.setSpec_id(orderVo.getBoxSkuId().equals("") ? orderVo.getSkuId() : orderVo.getBoxSkuId());
            orderSkuParam.setGoods_no(orderVo.getSpuErpCode());
            orderSkuParam.setSpec_no(orderVo.getSkuErpCode());
            orderSkuParam.setGoods_name(spuVo.getName());
            orderSkuParam.setAdjust_amount(BigDecimal.ZERO);
            orderSkuParam.setDiscount(BigDecimal.ZERO);
            orderSkuParam.setShare_discount(skuVo.getPrice().multiply(BigDecimal.valueOf(orderVo.getNum())).subtract(orderVo.getPriceActual()));
            listOrderSku.add(orderSkuParam);

            //配置订单维度数据
            tradeListParam.setOrder_list(listOrderSku);
            tradeListParam.setTid(orderVo.getOrderCode());
            tradeListParam.setTrade_status(ErpEnum.WdtStatus.STATUS_UN_SEND.WdtStatus());
            tradeListParam.setPay_status(2);
            tradeListParam.setDelivery_term(1);
            tradeListParam.setTrade_time(orderVo.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            tradeListParam.setPay_time(orderVo.getPayTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            tradeListParam.setBuyer_nick(orderVo.getUserName());
            tradeListParam.setPay_id(orderVo.getPayCode());
            tradeListParam.setReceiver_name("正在映画");
            tradeListParam.setReceiver_province("北京市");
            tradeListParam.setReceiver_city("北京市");
            tradeListParam.setReceiver_district("朝阳区");
            tradeListParam.setReceiver_address("广渠路 创1985园区  3-12");
            tradeListParam.setReceiver_mobile("15901093014");
            tradeListParam.setPost_amount(BigDecimal.ZERO);
            tradeListParam.setExt_cod_fee(BigDecimal.ZERO);
            tradeListParam.setOther_amount(BigDecimal.ZERO);
            tradeListParam.setPaid(orderVo.getPriceActual());
            tradeListParam.setWarehouse_no(orderVo.getErpWarehouseNo());
            listOrder.add(tradeListParam);
        }
        return listOrder;
    }


    @Override
    public ResponseDto<Boolean> syncErpLogistic() {
        Map<String, String> paramSync = CollectionUtil.linkMapStringString();
        paramSync.put("shop_no", shopNo);
        paramSync.put("limit", "100");
        String jsonSyc = erpWdtClient.execute(ErpEnum.WdtAPI.LOGISTICS_SYNC_QUERY.getUri(), paramSync);
        LogisticSyncBaseVo dataSyc = JsonUtils.fromJson(jsonSyc, LogisticSyncBaseVo.class);
        //处理平台发货
        List<LogisticsSyncVo> logisticsSyncVos = dataSyc.getTrades();
        List<LogisticsListParam> listParams = ObjectUtil.logisticsListParam();
        for (LogisticsSyncVo vo : logisticsSyncVos) {
            String orderCode = vo.getTid();
            String mailNo = vo.getLogistics_no();
            int recId = vo.getRec_id();
            String code;
            try {
                ResponseDto<Boolean> response = goblinStoreOrderService.express("", null, mailNo, "ERP", orderCode);
                code = response.getCode();
            } catch (Exception e) {
                e.printStackTrace();
                code = "1";
            }
            LogisticsListParam ack = LogisticsListParam.getNew();
            ack.setRec_id(recId);
            if ("0".equals(code)) {
                ack.setStatus(0);
                ack.setMessage("正在现场物流同步成功");
            } else {
                ack.setStatus(1);
                ack.setMessage("正在现场物流同步失败");
            }
            listParams.add(ack);
        }

        //确认物流同步 ACK
        if (listParams.size() > 0) {
            Map<String, String> paramAck = CollectionUtil.linkMapStringString();
            paramAck.put("shop_no", shopNo);
            paramAck.put("limit", "100");
            paramAck.put("logistics_list", JSON.toJSONString(listParams));
            String jsonAck = erpWdtClient.execute(ErpEnum.WdtAPI.LOGISTICS_SYNC_ACK.getUri(), paramAck);
            LogisticSyncAckBaseVo dataAck = JsonUtils.fromJson(jsonAck, LogisticSyncAckBaseVo.class);
        }
        return ResponseDto.success();
    }
}
