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

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageInfo;
import com.liquidnet.commons.lang.util.*;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.goblin.constant.GoblinStatusConst;
import com.liquidnet.service.goblin.dto.vo.*;
import com.liquidnet.service.goblin.entity.GoblinBackOrder;
import com.liquidnet.service.goblin.entity.GoblinBackOrderLog;
import com.liquidnet.service.goblin.entity.GoblinOrderOperationLog;
import com.liquidnet.service.goblin.param.RefundCallbackParam;
import com.liquidnet.service.goblin.service.manage.IGoblinStoreMoneyService;
import com.liquidnet.service.goblin.service.manage.IGoblinStoreOrderService;
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 com.mongodb.BasicDBObject;
import com.mongodb.client.result.UpdateResult;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class GoblinStoreOrderServiceImpl implements IGoblinStoreOrderService {

    @Autowired
    GoblinRedisUtils redisUtils;
    @Autowired
    GoblinMongoUtils mongoUtils;
    @Autowired
    QueueUtils queueUtils;
    @Value("${liquidnet.service.order.url-pay.goblinRefundUrl}")
    private String synUrl;
    @Value("${liquidnet.service.dragon.urls.refundApply}")
    private String refundApply;

    @Override
    public ResponseDto<PageInfo<GoblinStoreOrderListVo>> orderList(Integer page, String orderCode, Integer type, String cst, String cet, String expressContacts, String phone, Integer status) {
        List<GoblinStoreOrderListVo> listVos = ObjectUtil.getGoblinStoreOrderListVoArrayList();
        String uid = CurrentUtil.getCurrentUid();
        GoblinStoreInfoVo storeInfoVo = redisUtils.getStoreInfoVoByUid(uid);
        if (storeInfoVo == null) {
            return ResponseDto.failure("无法查看");
        }
        HashMap<String, Object> map = mongoUtils.storeOrderList(storeInfoVo.getStoreId(), page, orderCode, cst, cet, expressContacts, phone, status);
        long total = (long) map.get("total");
        List<GoblinStoreOrderVo> voList = (List<GoblinStoreOrderVo>) map.get("data");
        for (GoblinStoreOrderVo item : voList) {
            GoblinStoreOrderListVo vo = GoblinStoreOrderListVo.getNew();
            vo.setCreatedAt(item.getCreatedAt());
            vo.setExpressAddressDetail(item.getOrderAttrVo().getExpressAddressDetail());
            vo.setExpressContacts(item.getOrderAttrVo().getExpressContacts());
            vo.setExpressPhone(item.getOrderAttrVo().getExpressPhone());
            vo.setOrderCode(item.getOrderCode());
            vo.setExpressAddress(item.getOrderAttrVo().getExpressAddress());
            vo.setOrderId(item.getOrderId());
            vo.setPayType(item.getPayType());
            vo.setPriceActual(item.getPriceActual());
            vo.setStatus(item.getStatus());
            vo.setPriceExpress(item.getPriceExpress());
            List<GoblinStoreOrderListSkuVo> orderListSkuVos = ObjectUtil.getGoblinStoreOrderListSkuVoArrayList();
            for (String skuId : item.getOrderSkuVoIds()) {
                GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(skuId);
                GoblinStoreOrderListSkuVo itemSkuVo = GoblinStoreOrderListSkuVo.getNew();
                itemSkuVo.setNum(orderSkuVo.getNum());
                itemSkuVo.setOrderSkuId(orderSkuVo.getOrderSkuId());
                itemSkuVo.setSkuId(orderSkuVo.getSkuId());
                itemSkuVo.setSkuName(orderSkuVo.getSkuName());
                itemSkuVo.setSkuPriceActual(orderSkuVo.getSkuPriceActual());
                itemSkuVo.setSkuSpecs(orderSkuVo.getSkuSpecs());
                itemSkuVo.setSkuImage(orderSkuVo.getSkuImage());
                itemSkuVo.setStatus(orderSkuVo.getStatus());
                orderListSkuVos.add(itemSkuVo);
            }
            vo.setStoreOrderListSkuVoList(orderListSkuVos);
            listVos.add(vo);
        }
        PageInfo<GoblinStoreOrderListVo> pageInfo = new PageInfo(listVos);
        pageInfo.setTotal(total);
        return ResponseDto.success(pageInfo);
    }

    @Override
    public ResponseDto<GoblinStoreOrderListVo> orderDetails(String orderId) {
        String uid = CurrentUtil.getCurrentUid();
        GoblinStoreInfoVo storeInfoVo = redisUtils.getStoreInfoVoByUid(uid);
        if (storeInfoVo == null) {
            return ResponseDto.failure("无法查看");
        }
        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
        GoblinStoreOrderListVo vo = GoblinStoreOrderListVo.getNew();
        vo.setCreatedAt(orderVo.getCreatedAt());
        vo.setExpressAddressDetail(orderVo.getOrderAttrVo().getExpressAddressDetail());
        vo.setExpressContacts(orderVo.getOrderAttrVo().getExpressContacts());
        vo.setExpressPhone(orderVo.getOrderAttrVo().getExpressPhone());
        vo.setOrderCode(orderVo.getOrderCode());
        vo.setExpressAddress(orderVo.getOrderAttrVo().getExpressAddress());
        vo.setOrderId(orderVo.getOrderId());
        vo.setPayType(orderVo.getPayType());
        vo.setPriceActual(orderVo.getPriceActual());
        vo.setStatus(orderVo.getStatus());
        vo.setPayTime(orderVo.getPayTime());
        vo.setPriceExpress(orderVo.getPriceExpress());
        vo.setLogisticsCompany(orderVo.getLogisticsCompany());
        List<GoblinStoreOrderListSkuVo> orderListSkuVos = ObjectUtil.getGoblinStoreOrderListSkuVoArrayList();
        for (String skuId : orderVo.getOrderSkuVoIds()) {
            GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(skuId);
            GoblinStoreOrderListSkuVo itemSkuVo = GoblinStoreOrderListSkuVo.getNew();
            itemSkuVo.setNum(orderSkuVo.getNum());
            itemSkuVo.setOrderSkuId(orderSkuVo.getOrderSkuId());
            itemSkuVo.setSkuId(orderSkuVo.getSkuId());
            itemSkuVo.setSkuName(orderSkuVo.getSkuName());
            itemSkuVo.setSkuPriceActual(orderSkuVo.getSkuPriceActual());
            itemSkuVo.setSkuSpecs(orderSkuVo.getSkuSpecs());
            itemSkuVo.setSkuImage(orderSkuVo.getSkuImage());
            itemSkuVo.setStatus(orderSkuVo.getStatus());
            orderListSkuVos.add(itemSkuVo);
        }
        vo.setStoreOrderListSkuVoList(orderListSkuVos);
        return ResponseDto.success(vo);
    }

    @Override
    public ResponseDto<Boolean> orderCancel(String orderId) {
        String uid = CurrentUtil.getCurrentUid();
        LocalDateTime now = LocalDateTime.now();
        String nowStr = DateUtil.getNowTime();
        LinkedList<String> sqls = CollectionUtil.linkedListString();
        LinkedList<Object[]> sqlsOrder = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> sqlsOrderSku = CollectionUtil.linkedListObjectArr();
        sqls.add(SqlMapping.get("goblin_order.store.cancel"));
        sqls.add(SqlMapping.get("goblin_order.store.orderSkuStatus"));
        GoblinStoreInfoVo storeInfoVo = redisUtils.getStoreInfoVoByUid(uid);
        if (storeInfoVo == null) {
            return ResponseDto.failure("无法查看");
        }
        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
        if (orderVo == null || !orderVo.getStoreId().equals(storeInfoVo.getStoreId())) {
            return ResponseDto.failure("无法查看");
        }
        orderVo.setStatus(GoblinStatusConst.Status.ORDER_STATUS_5.getValue());
        orderVo.setCancelReason("商铺取消");
        orderVo.setCancelTime(nowStr);
        for (String orderSkuId : orderVo.getOrderSkuVoIds()) {
            GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
            orderSkuVo.setStatus(GoblinStatusConst.Status.ORDER_STATUS_5.getValue());
            //redis
            redisUtils.setGoblinOrderSku(orderSkuId, orderSkuVo);
            //mongo
            mongoUtils.updateGoblinOrderSkuVo(orderSkuId, orderSkuVo);
            //mysql
            sqlsOrderSku.add(new Object[]{
                    orderSkuVo.getStatus(), now,
                    orderSkuVo.getOrderSkuId(), now, now
            });
        }
        GoblinOrderOperationLog log = initLog(orderId, uid, now);
        log.setType(GoblinStatusConst.Status.ORDER_LOG_STATUS_14.getValue());
        log.setRemark("商铺取消订单");
        //redis
        redisUtils.setGoblinOrder(orderId, orderVo);
        //mongo
        mongoUtils.updateGoblinStoreOrderVo(orderId, orderVo);
        //mysql
        sqlsOrder.add(new Object[]{
                orderVo.getStatus(), now, orderVo.getCancelReason(), now,
                orderId, now, now
        });
        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.GOBLIN_STORE_ORDER_OPERA.getKey(),
                SqlMapping.gets(sqls, sqlsOrder, sqlsOrderSku));
        return ResponseDto.success();
    }

    @Override
    public ResponseDto<Boolean> changeExpressPrice(String orderId, BigDecimal price) {
        String uid = CurrentUtil.getCurrentUid();
        LocalDateTime now = LocalDateTime.now();
        GoblinStoreInfoVo storeInfoVo = redisUtils.getStoreInfoVoByUid(uid);
        if (storeInfoVo == null) {
            return ResponseDto.failure("无法查看");
        }
        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
        if (orderVo == null || !orderVo.getStoreId().equals(storeInfoVo.getStoreId())) {
            return ResponseDto.failure("无法查看");
        }
        if (orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_3.getValue()) {
            return ResponseDto.failure("已发货");
        }
        BigDecimal voucherExpress = orderVo.getPriceExpress().subtract(price);
        orderVo.setPriceTotal(orderVo.getPriceModify().add(voucherExpress));
        orderVo.setPriceModify(orderVo.getPriceModify().add(voucherExpress));
        orderVo.setPriceVoucher(orderVo.getPriceVoucher().add(voucherExpress));
        orderVo.setPriceActual(orderVo.getPriceActual().add(voucherExpress));
        orderVo.setPriceExpress(price);
        GoblinOrderOperationLog log = initLog(orderId, uid, now);
        log.setType(GoblinStatusConst.Status.ORDER_LOG_STATUS_17.getValue());
        log.setRemark("expressPress=[" + price + "]");
        //redis
        redisUtils.setGoblinOrder(orderId, orderVo);
        //mongo
        mongoUtils.updateGoblinStoreOrderVo(orderId, orderVo);
        //mysql
        queueUtils.sendMsgByRedis(
                MQConst.GoblinQueue.GOBLIN_STORE_ORDER_OPERA.getKey(),
                SqlMapping.get("goblin_order.store.orderExpressPrice",
                        orderVo.getPriceTotal(), orderVo.getPriceModify(), orderVo.getPriceVoucher(), orderVo.getPriceActual(), orderVo.getPriceExpress(), now,
                        orderId, now, now
                )
        );
        //添加日志
        queueUtils.sendMsgByRedis(
                MQConst.GoblinQueue.GOBLIN_STORE_ORDER_OPERA.getKey(),
                SqlMapping.get("goblin_order.store.log",
                        log.getOrderLogId(), log.getOrderId(), log.getType(), log.getRemark(), log.getOperationName(), now
                )
        );
        return ResponseDto.success();
    }

    @Override
    public ResponseDto<Boolean> changeAddress(String orderId, String expressAddressDetail, String expressContacts, String expressPhone) {
        String uid = CurrentUtil.getCurrentUid();
        LocalDateTime now = LocalDateTime.now();
        GoblinStoreInfoVo storeInfoVo = redisUtils.getStoreInfoVoByUid(uid);
        if (storeInfoVo == null) {
            return ResponseDto.failure("无法查看");
        }
        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
        if (orderVo == null || !orderVo.getStoreId().equals(storeInfoVo.getStoreId())) {
            return ResponseDto.failure("无法查看");
        }
        if (orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_3.getValue()) {
            return ResponseDto.failure("已发货");
        }
        orderVo.getOrderAttrVo().setExpressAddressDetail(expressAddressDetail);
        orderVo.getOrderAttrVo().setExpressContacts(expressContacts);
        orderVo.getOrderAttrVo().setExpressPhone(expressPhone);
        GoblinOrderOperationLog log = initLog(orderId, uid, now);
        log.setType(GoblinStatusConst.Status.ORDER_LOG_STATUS_17.getValue());
        log.setRemark("expressContacts=[" + expressContacts + "],expressPhone=[" + expressPhone + "],expressAddressDetail=[" + expressAddressDetail + "]");
        //redis
        redisUtils.setGoblinOrder(orderId, orderVo);
        //mongo
        mongoUtils.updateGoblinStoreOrderVo(orderId, orderVo);
        //mysql
        queueUtils.sendMsgByRedis(
                MQConst.GoblinQueue.GOBLIN_STORE_ORDER_OPERA.getKey(),
                SqlMapping.get("goblin_order.store.address",
                        expressContacts, expressPhone, expressAddressDetail, now, orderId, now, now
                )
        );
        //添加日志
        queueUtils.sendMsgByRedis(
                MQConst.GoblinQueue.GOBLIN_STORE_ORDER_OPERA.getKey(),
                SqlMapping.get("goblin_order.store.log",
                        log.getOrderLogId(), log.getOrderId(), log.getType(), log.getRemark(), log.getOperationName(), now
                )
        );
        return ResponseDto.success();
    }

    @Override
    public ResponseDto<Boolean> changeSkuPrice(String orderId, String orderSkuId, BigDecimal price) {
        String uid = CurrentUtil.getCurrentUid();
        LocalDateTime now = LocalDateTime.now();
        GoblinStoreInfoVo storeInfoVo = redisUtils.getStoreInfoVoByUid(uid);
        if (storeInfoVo == null) {
            return ResponseDto.failure("无法查看");
        }
        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
        if (orderVo == null || !orderVo.getStoreId().equals(storeInfoVo.getStoreId())) {
            return ResponseDto.failure("无法查看");
        }
        if (orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_0.getValue()) {
            return ResponseDto.failure("已发货");
        }
        GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
        if (orderSkuVo == null) {
            return ResponseDto.failure("不存在");
        }
        BigDecimal voucherPrice = orderSkuVo.getSkuPriceActual().subtract(price);
        orderSkuVo.setPriceModify(price);
        orderSkuVo.setPriceVoucher(orderSkuVo.getPriceVoucher().add(voucherPrice));
        orderSkuVo.setSkuPriceActual(orderSkuVo.getSkuPriceActual().subtract(voucherPrice));
        orderVo.setPriceTotal(orderVo.getPriceTotal().subtract(voucherPrice));
        orderVo.setPriceModify(orderVo.getPriceModify().add(voucherPrice));
        orderVo.setPriceVoucher(orderVo.getPriceVoucher().add(voucherPrice));
        orderVo.setPriceActual(orderVo.getPriceActual().subtract(voucherPrice));
        GoblinOrderOperationLog log = initLog(orderId, uid, now);
        log.setType(GoblinStatusConst.Status.ORDER_LOG_STATUS_12.getValue());
        log.setRemark("orderSkuId=[" + orderSkuId + "],price=[" + price + "]");
        //redis
        redisUtils.setGoblinOrder(orderId, orderVo);
        redisUtils.setGoblinOrderSku(orderSkuId, orderSkuVo);
        //mongo
        mongoUtils.updateGoblinStoreOrderVo(orderId, orderVo);
        mongoUtils.updateGoblinOrderSkuVo(orderSkuId, orderSkuVo);
        //mysql
        LinkedList<String> sqls = CollectionUtil.linkedListString();
        LinkedList<Object[]> sqlsOrder = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> sqlsOrderSku = CollectionUtil.linkedListObjectArr();
        sqls.add(SqlMapping.get("goblin_order.store.orderPrice"));
        sqls.add(SqlMapping.get("goblin_order.store.orderSkuPrice"));
        sqlsOrder.add(new Object[]{
                orderVo.getPriceModify(), orderVo.getPriceVoucher(), orderVo.getPriceActual(), now,
                orderId, now, now
        });
        sqlsOrderSku.add(new Object[]{
                orderSkuVo.getPriceModify(), orderSkuVo.getPriceVoucher(), orderSkuVo.getSkuPriceActual(), now,
                orderSkuId, now, now
        });
        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.GOBLIN_STORE_ORDER_OPERA.getKey(),
                SqlMapping.gets(sqls, sqlsOrder, sqlsOrderSku));
        //添加日志
        queueUtils.sendMsgByRedis(
                MQConst.GoblinQueue.GOBLIN_STORE_ORDER_OPERA.getKey(),
                SqlMapping.get("goblin_order.store.log",
                        log.getOrderLogId(), log.getOrderId(), log.getType(), log.getRemark(), log.getOperationName(), now
                )
        );
        return ResponseDto.success();
    }

    @Override
    public ResponseDto<Boolean> refundOrderSku(String orderId, String orderSkuId, BigDecimal price) {
        String uid = CurrentUtil.getCurrentUid();
        LocalDateTime now = LocalDateTime.now();
        String nowStr = DateUtil.getNowTime();
        GoblinStoreInfoVo storeInfoVo = redisUtils.getStoreInfoVoByUid(uid);
        if (storeInfoVo == null) {
            return ResponseDto.failure("无法查看");
        }
        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
        if (orderVo == null || !orderVo.getStoreId().equals(storeInfoVo.getStoreId())) {
            return ResponseDto.failure("无法查看");
        }
        GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
        if (orderSkuVo == null) {
            return ResponseDto.failure("不存在");
        }
        //记录退款单
        String refundCode = IDGenerator.storeRefundCode(orderVo.getMasterOrderCode());
        GoblinBackOrder goblinBackOrder = GoblinBackOrder.getNew();
        goblinBackOrder.setBackOrderId(IDGenerator.nextTimeId2());
        goblinBackOrder.setBackCode(refundCode);
        goblinBackOrder.setOrderId(orderVo.getOrderId());
        goblinBackOrder.setOrderCode(orderVo.getOrderCode());
        goblinBackOrder.setStoreId(orderVo.getStoreId());
        goblinBackOrder.setUserId(orderVo.getUserId());
        goblinBackOrder.setSkuIdNums(orderSkuId);
        goblinBackOrder.setType(GoblinStatusConst.Type.BACK_TYPE_1.getValue());
        goblinBackOrder.setReason(GoblinStatusConst.Type.BACK_REASON_TYPE_8.getDesc());
        goblinBackOrder.setDescribes("店铺退款");
        goblinBackOrder.setRealBackPrice(price);
        goblinBackOrder.setStatus(GoblinStatusConst.Status.ORDER_BACK_STATUS_0.getValue());
        goblinBackOrder.setAuditAt(now);
        goblinBackOrder.setCreatedAt(now);
        GoblinBackOrderVo backOrderVo = GoblinBackOrderVo.getNew();
        BeanUtils.copyProperties(goblinBackOrder, backOrderVo);
        backOrderVo.setCreatedAt(nowStr);

        GoblinBackOrderSkuVo backOrderSkuVo = GoblinBackOrderSkuVo.getNew();
        backOrderSkuVo.setOrderSkuId(orderSkuId);
        backOrderSkuVo.setSpuId(orderSkuVo.getSpuId());
        backOrderSkuVo.setSpuName(orderSkuVo.getSpuName());
        backOrderSkuVo.setSkuId(orderSkuVo.getSkuId());
        backOrderSkuVo.setSkuName(orderSkuVo.getSkuName());
        backOrderSkuVo.setRefundPrice(price);
        backOrderSkuVo.setSkuSpecs(orderSkuVo.getSkuSpecs());
        backOrderSkuVo.setCreatedAt(nowStr);
        List<GoblinBackOrderSkuVo> orderSkuVoList = ObjectUtil.goblinBackOrderSkuVoArrayList();
        orderSkuVoList.add(backOrderSkuVo);
        backOrderVo.setBackOrderSkuVos(orderSkuVoList);
        //添加日志
        GoblinBackOrderLog backOrderLog = initBackLog(goblinBackOrder.getBackOrderId(), uid, now);
        backOrderLog.setStatus(GoblinStatusConst.Status.ORDER_LOG_STATUS_22.getValue());
        backOrderLog.setOperationType(GoblinStatusConst.Type.OPERATION_TYPE_2.getValue());
        backOrderLog.setMessage("商户发起：orderSkuId=[" + orderSkuId + "],price=[" + price + "],[refundCode=" + refundCode + "]");
        //调用退款
        String returnString = initRefund(orderVo, price, refundCode);
        HashMap hashMapResult = JsonUtils.fromJson(returnString, HashMap.class);
        Boolean success = (Boolean) hashMapResult.get("success");
        String message = (String) hashMapResult.get("message");
        if (!success) {
            backOrderVo.setStatus(GoblinStatusConst.Status.ORDER_BACK_STATUS_10.getValue());
            backOrderVo.setReason(backOrderVo.getReason() + ",失败原因：" + message);
            log.error("REFUND DATA = " + returnString);
        }
        //redis
        redisUtils.setBackOrderVo(backOrderVo.getBackOrderId(), backOrderVo);
        redisUtils.addBackOrderByOrderId(orderVo.getOrderId(),backOrderVo.getBackOrderId());
        //mongo
        mongoUtils.insertGoblinBackOrderVo(backOrderVo);
        //添加退款
        queueUtils.sendMsgByRedis(
                MQConst.GoblinQueue.GOBLIN_STORE_ORDER_OPERA.getKey(),
                SqlMapping.get("goblin_order.store.backOrder",
                        goblinBackOrder.getBackOrderId(), goblinBackOrder.getBackCode(), goblinBackOrder.getOrderId(),
                        goblinBackOrder.getOrderCode(), goblinBackOrder.getStoreId(), goblinBackOrder.getUserId(),
                        goblinBackOrder.getSkuIdNums(), goblinBackOrder.getType(), goblinBackOrder.getReason(),
                        goblinBackOrder.getDescribes(), goblinBackOrder.getRealBackPrice(), goblinBackOrder.getStatus(),
                        goblinBackOrder.getCreatedAt(), goblinBackOrder.getAuditAt()
                )
        );
        //添加日志
        queueUtils.sendMsgByRedis(
                MQConst.GoblinQueue.GOBLIN_STORE_ORDER_OPERA.getKey(),
                SqlMapping.get("goblin_order.store.refundLog",
                        backOrderLog.getBackOrderLogId(), backOrderLog.getBackOrderId(), backOrderLog.getOperationType(),
                        backOrderLog.getMessage(), backOrderLog.getOperationName(), backOrderLog.getStatus(), now
                )
        );
        if (success) {
            return ResponseDto.success();
        }
        return ResponseDto.failure("退款失败:" + message);
    }

    @Override
    public ResponseDto<Boolean> express(String orderId, String mailNo) {
        String uid = CurrentUtil.getCurrentUid();
        LocalDateTime now = LocalDateTime.now();
        String nowStr = DateUtil.getNowTime();
        LinkedList<String> sqls = CollectionUtil.linkedListString();
        LinkedList<Object[]> sqlsOrder = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> sqlsOrderSku = CollectionUtil.linkedListObjectArr();
        sqls.add(SqlMapping.get("goblin_order.store.express"));
        sqls.add(SqlMapping.get("goblin_order.store.orderSkuStatus"));
        GoblinStoreInfoVo storeInfoVo = redisUtils.getStoreInfoVoByUid(uid);
        if (storeInfoVo == null) {
            return ResponseDto.failure("无法查看");
        }
        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
        if (orderVo == null || !orderVo.getStoreId().equals(storeInfoVo.getStoreId())) {
            return ResponseDto.failure("无法查看");
        }
        if (orderVo.getStatus() != GoblinStatusConst.Status.ORDER_STATUS_2.getValue()) {
            return ResponseDto.failure("无法发货");
        }
        orderVo.setMailNo(mailNo);
        orderVo.setDeliveryTime(nowStr);
        orderVo.setLogisticsCompany("松鼠德邦");
        orderVo.setStatus(GoblinStatusConst.Status.ORDER_STATUS_3.getValue());
        for (String orderSkuId : orderVo.getOrderSkuVoIds()) {
            GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
            orderSkuVo.setStatus(GoblinStatusConst.Status.ORDER_STATUS_3.getValue());
            //redis
            redisUtils.setGoblinOrderSku(orderSkuId, orderSkuVo);
            //mongo
            mongoUtils.updateGoblinOrderSkuVo(orderSkuId, orderSkuVo);
            //mysql
            sqlsOrderSku.add(new Object[]{
                    orderSkuVo.getStatus(), now,
                    orderSkuVo.getOrderSkuId(), now, now
            });
        }
        GoblinOrderOperationLog log = initLog(orderId, uid, now);
        log.setType(GoblinStatusConst.Status.ORDER_LOG_STATUS_13.getValue());
        log.setRemark("发货：orderId=[" + orderId + "],mailNo=[" + mailNo + "]");

        //redis
        redisUtils.setGoblinOrder(orderId, orderVo);
        //mongo
        mongoUtils.updateGoblinStoreOrderVo(orderId, orderVo);
        //mysql
        sqlsOrder.add(new Object[]{
                orderVo.getMailNo(), orderVo.getDeliveryTime(), orderVo.getLogisticsCompany(), orderVo.getStatus(), now, orderId, now, now
        });
        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.GOBLIN_STORE_ORDER_OPERA.getKey(),
                SqlMapping.gets(sqls, sqlsOrder, sqlsOrderSku));
        //添加日志
        queueUtils.sendMsgByRedis(
                MQConst.GoblinQueue.GOBLIN_STORE_ORDER_OPERA.getKey(),
                SqlMapping.get("goblin_order.store.log",
                        log.getOrderLogId(), log.getOrderId(), log.getType(), log.getRemark(), log.getOperationName(), now
                )
        );
        return ResponseDto.success();
    }

    @Override
    public String refundSyncOrder(RefundCallbackParam refundCallbackParam) {
        LocalDateTime now = LocalDateTime.now();
        String nowStr = DateUtil.getNowTime();
        log.info("refundCallback订单退款回调参数: [RefundCallbackParam={}]", refundCallbackParam);
        GoblinBackOrderVo backOrderVo = mongoUtils.getGoblinBackOrderVoByBackCode(refundCallbackParam.getRefundCode());
        if (backOrderVo == null) {
            log.info("refundCallback: 退款订单查询失败，编号{}", refundCallbackParam.getOrderRefundCode());
            return "fail";
        }
        if (backOrderVo.getStatus() == GoblinStatusConst.Status.ORDER_LOG_STATUS_20.getValue() || backOrderVo.getStatus() == GoblinStatusConst.Status.ORDER_LOG_STATUS_201.getValue()) {
            log.info("refundCallback: 退款订单已取消，编号{}", refundCallbackParam.getOrderRefundCode());
            return "fail";
        }
        if (backOrderVo.getStatus() == GoblinStatusConst.Status.ORDER_LOG_STATUS_22.getValue()) {
            log.info("refundCallback: 退款订单已完成，编号{}", refundCallbackParam.getOrderRefundCode());
            return "success";
        }
        Integer status = refundCallbackParam.getStatus();
        if (1 == status) { // 退款成功
            LinkedList<String> sqls = CollectionUtil.linkedListString();
            LinkedList<Object[]> sqlsOrder = CollectionUtil.linkedListObjectArr();
            LinkedList<Object[]> sqlsOrderSku = CollectionUtil.linkedListObjectArr();
            LinkedList<Object[]> sqlsBackOrder = CollectionUtil.linkedListObjectArr();
            sqls.add(SqlMapping.get("goblin_order.store.refundPrice"));
            sqls.add(SqlMapping.get("goblin_order.store.refundSkuPrice"));
            sqls.add(SqlMapping.get("goblin_order.store.refundBackOrder"));
            String orderId = backOrderVo.getOrderId();
            List<GoblinBackOrderSkuVo> backOrderSkuVos = backOrderVo.getBackOrderSkuVos();
            BigDecimal price = refundCallbackParam.getRefundPrice();
            GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
            orderVo.setPriceRefund(orderVo.getPriceRefund().add(price));
            if (orderVo.getPriceRefund().compareTo(orderVo.getPriceActual()) == 0) {
                orderVo.setStatus(GoblinStatusConst.Status.ORDER_STATUS_6.getValue());
            }
            backOrderVo.setStatus(GoblinStatusConst.Status.ORDER_BACK_STATUS_2.getValue());
            backOrderVo.setRefundAt(nowStr);
            for (GoblinBackOrderSkuVo backOrderSkuVo : backOrderSkuVos) {
                GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(backOrderSkuVo.getOrderSkuId());
                orderSkuVo.setPriceRefund(orderSkuVo.getPriceRefund().add(price));
                if (orderSkuVo.getPriceRefund().compareTo(orderSkuVo.getSkuPriceActual()) == 0) {
                    orderSkuVo.setStatus(GoblinStatusConst.Status.ORDER_STATUS_6.getValue());
                    String pre = GoblinStatusConst.MarketPreStatus.getPre(orderSkuVo.getSkuId());
                    String skuId = orderSkuVo.getSkuId();
                    if (pre != null) {
                        skuId = orderSkuVo.getSkuId().split(pre)[0];
                    }
                    redisUtils.incrSkuStock(pre, skuId, orderSkuVo.getNum());
                }
                redisUtils.setGoblinOrderSku(backOrderSkuVo.getOrderSkuId(), orderSkuVo);
                mongoUtils.updateGoblinOrderSkuVo(backOrderSkuVo.getOrderSkuId(), orderSkuVo);
                sqlsOrderSku.add(new Object[]{
                        orderSkuVo.getPriceRefund(), orderSkuVo.getStatus(), now,
                        backOrderSkuVo.getOrderSkuId(), now, now
                });
                GoblinOrderLogVo logVo = GoblinOrderLogVo.getNew();
                logVo.setOrderId(orderVo.getOrderId());
                logVo.setOrderCode(orderVo.getOrderCode());
                logVo.setPayCode(orderVo.getPayCode());
                if (orderSkuVo.getSkuId().indexOf(GoblinStatusConst.MarketPreStatus.MARKET_PRE_PURCHASE.getValue()) > 0) {
                    logVo.setOrderType("zhengzai");
                } else {
                    logVo.setOrderType("order");
                }
                logVo.setStoreId(orderVo.getStoreId());
                logVo.setSpuId(orderSkuVo.getSpuId());
                logVo.setSpuName(backOrderSkuVo.getSpuName());
                logVo.setSkuId(backOrderSkuVo.getSkuId());
                logVo.setSkuPriceActual(price.multiply(BigDecimal.valueOf(100)).negate().longValue());
                logVo.setStatus(GoblinStatusConst.Status.ORDER_LOG_STATUS_22.getValue());
                logVo.setOperationId(backOrderVo.getUserId());
                logVo.setOperationType(GoblinStatusConst.Type.OPERATION_TYPE_2.getValue());
                logVo.setCreatedAt(now);
                mongoUtils.insertGoblinOrderLogVo(logVo);
            }
            //redis
            redisUtils.setGoblinOrder(orderId, orderVo);
            //mongo
            mongoUtils.updateGoblinStoreOrderVo(orderId, orderVo);
            //mysql
            sqlsOrder.add(new Object[]{
                    orderVo.getPriceRefund(), orderVo.getStatus(), now,
                    orderId, now, now
            });
            sqlsBackOrder.add(new Object[]{
                    backOrderVo.getStatus(), now, now, backOrderVo.getBackOrderId(), now, now
            });
            queueUtils.sendMsgByRedis(MQConst.GoblinQueue.GOBLIN_STORE_ORDER_OPERA.getKey(),
                    SqlMapping.gets(sqls, sqlsOrder, sqlsOrderSku, sqlsBackOrder));
        } else if (0 == status) {

        }
        return "success";
    }

    private GoblinOrderOperationLog initLog(String orderId, String uid, LocalDateTime now) {
        GoblinOrderOperationLog log = GoblinOrderOperationLog.getNew();
        log.setOrderId(orderId);
        log.setOperationName(uid);
        log.setOrderLogId(IDGenerator.nextTimeId2());
        log.setCreatedAt(now);
        return log;
    }

    private GoblinBackOrderLog initBackLog(String orderId, String uid, LocalDateTime now) {
        GoblinBackOrderLog log = GoblinBackOrderLog.getNew();
        log.setBackOrderId(orderId);
        log.setOperationName(uid);
        log.setBackOrderLogId(IDGenerator.nextTimeId2());
        log.setCreatedAt(now);
        return log;
    }

    private String initRefund(GoblinStoreOrderVo orderVo, BigDecimal price, String refundCode) {
        MultiValueMap<String, String> params = CollectionUtil.linkedMultiValueMapStringString();
        params.add("code", orderVo.getPayCode());
        params.add("notifyUrl", synUrl);
        params.add("orderCode", orderVo.getMasterOrderCode());
        params.add("orderRefundCode", refundCode);
        params.add("paymentId", orderVo.getPaymentId());
        params.add("paymentType", orderVo.getPaymentType());
        params.add("price", String.valueOf(price));
        params.add("priceTotal", String.valueOf(orderVo.getPriceActual()));
        params.add("reason", "按需退款");
        MultiValueMap<String, String> headers = CollectionUtil.linkedMultiValueMapStringString();
        headers.add("Accept", "application/json;charset=UTF-8");
        String returnString = HttpUtil.post(refundApply, params, headers);
        log.debug("REFUND DATA = " + returnString);
        return returnString;
    }
}
