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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.google.common.base.Joiner;
import com.liquidnet.commons.lang.util.*;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.candy.constant.CandyRedisConst;
import com.liquidnet.service.candy.dto.CandyUserCouponBasicDto;
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.GoblinStoreOrder;
import com.liquidnet.service.goblin.param.GoblinAppOrderRefundParam;
import com.liquidnet.service.goblin.service.IGoblinOrderAppService;
import com.liquidnet.service.goblin.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.IntStream;

import static com.liquidnet.commons.lang.util.DateUtil.DTF_YMD_HMS;
import static com.liquidnet.commons.lang.util.DateUtil.DTFYMDHMS;


@Service
@Slf4j
public class GoblinOrderAppServiceImpl implements IGoblinOrderAppService {

    @Autowired
    GoblinRedisUtils redisUtils;
    @Autowired
    GoblinMongoUtils mongoUtils;
    @Autowired
    QueueUtils queueUtils;
    @Autowired
    GoblinOrderUtils orderUtils;


    @Override
    public ResponseDto<PageInfo<GoblinAppOrderListVo>> orderList(int page, String pre) {
        String uid = CurrentUtil.getCurrentUid();
        List<GoblinAppOrderListVo> orderVoList = ObjectUtil.goblinAppOrderListVoArrayList();
        List<String> orderIds;
        if (pre == null) {
            orderIds = redisUtils.getOrderList(uid);
        } else if (pre.equals(GoblinStatusConst.MarketPreStatus.MARKET_PRE_ZHENGZAI.getValue())) {
            orderIds = redisUtils.getZhengzaiOrderList(uid);
        } else {
            return ResponseDto.failure("参数错误");
        }
        int size = 40;
        int finalCount = orderIds.size() - page * size;
        int initCount = orderIds.size() - (page - 1) * size - 1;
        if (finalCount <= 0) {
            finalCount = 0;
        }
        for (int i = initCount; i >= finalCount; i--) {
            String orderId = orderIds.get(i);
            GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
            GoblinAppOrderListVo vo = GoblinAppOrderListVo.getNew();
            BeanUtils.copyProperties(orderVo, vo);
            vo.setRestTime(getRestTime(orderVo));
            List<GoblinOrderSkuVo> skuVos = ObjectUtil.getGoblinOrderSkuVoArrayList();
            for (String orderSkuId : orderVo.getOrderSkuVoIds()) {
                GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
                skuVos.add(orderSkuVo);
            }
            vo.setOrderSkuVos(skuVos);
            orderVoList.add(vo);
        }
        PageInfo<GoblinAppOrderListVo> pageInfo = new PageInfo(orderVoList);
        pageInfo.setTotal(orderIds.size());
        return ResponseDto.success(pageInfo);
    }

    @Override
    public ResponseDto<List<GoblinAppOrderListVo>> orderListByMaster(String orderMasterCode) {
        String[] orderIdArray = redisUtils.getMasterCode(orderMasterCode);
        List<GoblinAppOrderListVo> orderVoList = ObjectUtil.goblinAppOrderListVoArrayList();
        for (String orderId : orderIdArray) {
            GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
            GoblinAppOrderListVo vo = GoblinAppOrderListVo.getNew();
            BeanUtils.copyProperties(orderVo, vo);
            vo.setRestTime(getRestTime(orderVo));
            List<GoblinOrderSkuVo> skuVos = ObjectUtil.getGoblinOrderSkuVoArrayList();
            for (String orderSkuId : orderVo.getOrderSkuVoIds()) {
                GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
                skuVos.add(orderSkuVo);
            }
            vo.setOrderSkuVos(skuVos);
            orderVoList.add(vo);
        }
        return ResponseDto.success(orderVoList);
    }

    @Override
    public ResponseDto<GoblinAppOrderDetailsVo> orderDetails(String orderId, String uid) {
        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);

        if (orderVo == null || (!orderVo.getUserId().equals(uid) && uid != null)) {
            return ResponseDto.failure(ErrorMapping.get("20003"));
        }
        GoblinAppOrderDetailsVo vo = GoblinAppOrderDetailsVo.getNew();
        vo.setStoreOrderVo(orderVo);
        List<GoblinOrderSkuVo> skuVos = ObjectUtil.getGoblinOrderSkuVoArrayList();
        for (String orderSkuId : orderVo.getOrderSkuVoIds()) {
            GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
            orderSkuVo.desensitize();// 商品订单页面展示-关联人信息脱敏
            skuVos.add(orderSkuVo);
        }
        LocalDateTime canRefundTime = getCanRefundTime(orderVo);
        if (canRefundTime == null) {
            vo.setCanRefund(0);
        } else {
            if (LocalDateTime.now().isAfter(canRefundTime)) {
                vo.setCanRefund(0);
            } else {
                vo.setCanRefund(1);
            }
        }
        List<String> orderRefundIds = redisUtils.getBackOrderByOrderId(orderId);
        if (orderRefundIds.size() > 0) {
            GoblinBackOrderVo backOrderVo = redisUtils.getBackOrderVo(orderRefundIds.get(orderRefundIds.size() - 1));
            vo.setRefundStatus(backOrderVo.getStatus());
            if (vo.getCanRefund() == 1 && backOrderVo.getRefuseSize() < 1 &&
                    (backOrderVo.getStatus() == 2 || backOrderVo.getStatus() == 3 || backOrderVo.getStatus() == 5) &&
                    (vo.getStoreOrderVo().getStatus() == GoblinStatusConst.Status.ORDER_STATUS_2.getValue() || vo.getStoreOrderVo().getStatus() == GoblinStatusConst.Status.ORDER_STATUS_4.getValue())) {

            } else {
                vo.setCanRefund(0);
            }
        } else {
            vo.setRefundStatus(-1);
        }
        List<GoblinMailVo> mailVos = redisUtils.getGoblinMail(orderId);
        for (GoblinMailVo mailVo : mailVos) {
            mailVo.setOrderSkuVos(null);
            mailVo.setOrderSkuVoIds(null);
        }
        vo.setMailVos(mailVos);
        vo.setRefuseSize(orderRefundIds.size());
        vo.setRestTime(getRestTime(orderVo));
        vo.setStoreOrderVo(orderVo);
        vo.setOrderSkuVos(skuVos);
        return ResponseDto.success(vo);
    }

    @Override
    public ResponseDto<Boolean> getProduce(String orderId, String uid) {
        LocalDateTime now = LocalDateTime.now();
        LinkedList<String> sqls = CollectionUtil.linkedListString();
        sqls.add(SqlMapping.get("goblin_order.store.orderStatus"));
        sqls.add(SqlMapping.get("goblin_order.store.orderSkuStatus"));
        LinkedList<Object[]> orderStatus = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> orderSkuStatus = CollectionUtil.linkedListObjectArr();

        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
        if (!orderVo.getUserId().equals(uid)) {
            return ResponseDto.failure("无权操作");
        }
        if (orderVo.getStatus() != GoblinStatusConst.Status.ORDER_STATUS_3.getValue()) {
            return ResponseDto.failure("不可操作");
        }
        //订单状态修改
        orderVo.setStatus(GoblinStatusConst.Status.ORDER_STATUS_4.getValue());
        orderStatus.add(new Object[]{
                orderVo.getStatus(), orderVo.getZhengzaiStatus(), now,
                orderVo.getOrderId(), now, now
        });
        for (String orderSkuId : orderVo.getOrderSkuVoIds()) {
            //订单款式状态修改
            GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
            orderSkuVo.setStatus(GoblinStatusConst.Status.ORDER_STATUS_4.getValue());
            //redis
            redisUtils.setGoblinOrderSku(orderSkuVo.getOrderSkuId(), orderSkuVo);
            //mongo
            mongoUtils.updateGoblinOrderSkuVo(orderSkuVo.getOrderSkuId(), orderSkuVo);
            orderSkuStatus.add(new Object[]{
                    orderSkuVo.getStatus(), now,
                    orderSkuVo.getOrderSkuId(), now, now
            });
        }
        //redis
        redisUtils.setGoblinOrder(orderId, orderVo);
        //mongo
        mongoUtils.updateGoblinStoreOrderVo(orderId, orderVo);
        //redis
        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.GOBLIN_USER_ORDER_OPERA.getKey(), SqlMapping.gets(sqls, orderStatus, orderSkuStatus));
        return ResponseDto.success(true);
    }

    @Override
    public ResponseDto<Boolean> applyRefund(GoblinAppOrderRefundParam param) {

        LinkedList<String> sqls = CollectionUtil.linkedListString();
        sqls.add(SqlMapping.get("goblin_order.user.applyRefund"));
        sqls.add(SqlMapping.get("goblin_order.store.orderStatus"));
        sqls.add(SqlMapping.get("goblin_order.store.orderSkuStatus"));
        sqls.add(SqlMapping.get("goblin_order.store.refundLog"));
        sqls.add(SqlMapping.get("candy_user_coupon.update_apply_refund"));

        LinkedList<Object[]> applyRefund = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> orderStatus = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> orderSkuStatus = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> refundLog = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> updateCandyUserCouponObjs = CollectionUtil.linkedListObjectArr();

        String uid = CurrentUtil.getCurrentUid();
        LocalDateTime now = LocalDateTime.now();
        String nowStr = DateUtil.getNowTime();
        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(param.getOrderId());
//        if (!orderVo.getUserId().equals(uid)) {
//            return ResponseDto.failure("无权操作");
//        }

        List<String> backOrderIds = redisUtils.getBackOrderByOrderId(param.getOrderId());
        for (String backOrderId : backOrderIds) {
            GoblinBackOrderVo backOrderVo = redisUtils.getBackOrderVo(backOrderId);
            if (!(backOrderVo.getStatus().equals(GoblinStatusConst.Status.ORDER_BACK_STATUS_3.getValue()) || backOrderVo.getStatus().equals(GoblinStatusConst.Status.ORDER_BACK_STATUS_5.getValue()) || backOrderVo.getStatus().equals(GoblinStatusConst.Status.ORDER_BACK_STATUS_9.getValue()))) {
                return ResponseDto.failure("申请失败");
            }
        }

        if (!(orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_2.getValue() ||
//                orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_3.getValue() ||
                orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_4.getValue())) {
            return ResponseDto.failure("不可操作");
        }
        //判断7天
        LocalDateTime canRefundTime = getCanRefundTime(orderVo);
        if (canRefundTime == null) {
            return ResponseDto.failure("申请失败");
        } else {
            if (LocalDateTime.now().isAfter(canRefundTime)) {
                return ResponseDto.failure("申请失败");
            }
        }

        //判断券
        if ((!(orderVo.getUcouponId() == null || orderVo.getUcouponId().equals("")) || !(orderVo.getStoreCouponId() == null || orderVo.getStoreCouponId().equals("")))
                && param.getOrderSkuId() != null) {
            return ResponseDto.failure("用券仅支持整单退款");
        }

        //退款订单生成
        GoblinBackOrder backOrder = GoblinBackOrder.getNew();
        backOrder.setBackOrderId(IDGenerator.nextTimeId2());
        backOrder.setBackCode(IDGenerator.storeRefundCode(orderVo.getMasterOrderCode()));
        backOrder.setOrderId(param.getOrderId());
        backOrder.setOrderCode(orderVo.getOrderCode());
        backOrder.setStoreId(orderVo.getStoreId());
        backOrder.setLogisCompanyName(param.getCompany());
        backOrder.setMailNo(param.getMailNo());
        backOrder.setUserId(orderVo.getUserId());
        backOrder.setType(GoblinStatusConst.Type.BACK_TYPE_1.getValue());
        backOrder.setStatus(GoblinStatusConst.Status.ORDER_BACK_STATUS_1.getValue());
        backOrder.setCreatedAt(now);
        if (orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_2.getValue()) {//未发货
            backOrder.setRealBackPrice(orderVo.getPriceActual());
            backOrder.setBackPriceExpress(orderVo.getPriceExpress());
            backOrder.setReason(param.getReason());
            backOrder.setPics(param.getPics());
            backOrder.setDescribes(param.getDescribes());
            backOrder.setSkuIdNums(Joiner.on(",").join(orderVo.getOrderSkuVoIds()));
        } else if (orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_4.getValue()) {//已完成
            if (param.getOrderSkuId() != null) {
                GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(param.getOrderSkuId());
                if (orderVo.getPriceRefund().add(orderSkuVo.getSkuPriceActual()).add(orderVo.getPriceExpress()).compareTo(orderVo.getPriceActual()) >= 0) {
                    backOrder.setRealBackPrice(orderSkuVo.getSkuPriceActual().add(orderVo.getPriceExpress()));
                    backOrder.setBackPriceExpress(orderVo.getPriceExpress());
                } else {
                    backOrder.setRealBackPrice(orderSkuVo.getSkuPriceActual());
                    backOrder.setBackPriceExpress(BigDecimal.ZERO);
                }
            } else {
                backOrder.setRealBackPrice(orderVo.getPriceActual());
                backOrder.setBackPriceExpress(orderVo.getPriceExpress());
            }
            backOrder.setReason(param.getReason());
            backOrder.setPics(param.getPics());
            backOrder.setDescribes(param.getDescribes());
            backOrder.setType(param.getRefundType());
            backOrder.setSkuIdNums(param.getOrderSkuId());
        } else {
            return ResponseDto.failure("不可申请");
        }
        GoblinBackOrderVo vo = GoblinBackOrderVo.getNew();
        BeanUtils.copyProperties(backOrder, vo);
        vo.setCreatedAt(nowStr);
        List<GoblinBackOrderSkuVo> orderSkuVoList = ObjectUtil.goblinBackOrderSkuVoArrayList();
        if (orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_2.getValue()) {
            //订单状态修改
//            orderVo.setStatus(GoblinStatusConst.Status.ORDER_STATUS_61.getValue());
            orderStatus.add(new Object[]{
                    orderVo.getStatus(), orderVo.getZhengzaiStatus(),now,
                    orderVo.getOrderId(), now, now
            });
            for (String orderSkuId : orderVo.getOrderSkuVoIds()) {
                //订单款式状态修改
                GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
                orderSkuVo.setStatus(GoblinStatusConst.Status.ORDER_STATUS_61.getValue());
                GoblinBackOrderSkuVo backOrderSkuVo = GoblinBackOrderSkuVo.getNew();
                backOrderSkuVo.setOrderSkuId(orderSkuId);
                backOrderSkuVo.setSpuId(orderSkuVo.getSpuId());
                backOrderSkuVo.setSpuName(orderSkuVo.getSpuName());
                backOrderSkuVo.setSkuId(orderSkuVo.getSkuId());
                backOrderSkuVo.setSkuPic(orderSkuVo.getSkuImage());
                backOrderSkuVo.setSkuName(orderSkuVo.getSkuName());
                backOrderSkuVo.setSkuSpecs(orderSkuVo.getSkuSpecs());
                backOrderSkuVo.setRefundPrice(orderSkuVo.getSkuPriceActual());
                backOrderSkuVo.setCreatedAt(nowStr);
                orderSkuVoList.add(backOrderSkuVo);
                backOrderLog(orderVo, orderSkuVo, now);
                //redis
                redisUtils.setGoblinOrderSku(orderSkuVo.getOrderSkuId(), orderSkuVo);
                //mongo
                mongoUtils.updateGoblinOrderSkuVo(orderSkuVo.getOrderSkuId(), orderSkuVo);
                orderSkuStatus.add(new Object[]{
                        orderSkuVo.getStatus(), now,
                        orderSkuVo.getOrderSkuId(), now, now
                });
            }
        } else if (orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_4.getValue()) {
            if (param.getOrderSkuId() != null) {
                GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(param.getOrderSkuId());
                if (2 == orderSkuVo.getSkuType()) {// 券类商品-校验发放的券是否已使用
                    // 券类商品默认一个商品对应一个券，下单只可购买一张
                    String ucKey = CandyRedisConst.BASIC_USER_COUPON.concat(orderVo.getUserId());
                    List<CandyUserCouponBasicDto> vos = (List<CandyUserCouponBasicDto>) redisUtils.get(ucKey);
                    int idx = IntStream.range(0, vos.size())
                            .filter(i -> vos.get(i).getUcouponId().equals(orderSkuVo.getOrderSkuId())).findFirst().orElse(-1);
                    if (-1 != idx) {
                        CandyUserCouponBasicDto basicDto = vos.get(idx);
                        if (5 == basicDto.getState()) {// 券状态为'5-已使用'，则不可退款
                            return ResponseDto.failure("券已使用，不可申请");
                        }
                        basicDto.setState(2);// 置为'2-无效'，防止用户在后台审核过程中使用券，造成券已使用，订单也退款
                        vos.set(idx, basicDto);
                        redisUtils.redisUtil.set(ucKey, vos);
                        updateCandyUserCouponObjs.add(new Object[]{basicDto.getState(), orderVo.getUserId(), now, basicDto.getUcouponId()});
                    } else {
                        log.warn("券类商品订单申请退款，未找到对应券[orderSkuId={},uid={}]", orderSkuVo.getOrderSkuId(), orderVo.getUserId());
                    }
                }
                //订单款式状态修改
                orderSkuVo.setStatus(GoblinStatusConst.Status.ORDER_STATUS_61.getValue());
                GoblinBackOrderSkuVo backOrderSkuVo = GoblinBackOrderSkuVo.getNew();
                backOrderSkuVo.setOrderSkuId(param.getOrderSkuId());
                backOrderSkuVo.setSpuId(orderSkuVo.getSpuId());
                backOrderSkuVo.setSpuName(orderSkuVo.getSpuName());
                backOrderSkuVo.setSkuId(orderSkuVo.getSkuId());
                backOrderSkuVo.setSkuPic(orderSkuVo.getSkuImage());
                backOrderSkuVo.setSkuName(orderSkuVo.getSkuName());
                backOrderSkuVo.setRefundPrice(orderSkuVo.getSkuPriceActual());
                backOrderSkuVo.setSkuSpecs(orderSkuVo.getSkuSpecs());
                backOrderSkuVo.setCreatedAt(nowStr);
                backOrderSkuVo.setSkuType(orderSkuVo.getSkuType());
                orderSkuVoList.add(backOrderSkuVo);
                backOrderLog(orderVo, orderSkuVo, now);
                //redis
                redisUtils.setGoblinOrderSku(orderSkuVo.getOrderSkuId(), orderSkuVo);
                //mongo
                mongoUtils.updateGoblinOrderSkuVo(orderSkuVo.getOrderSkuId(), orderSkuVo);
                orderSkuStatus.add(new Object[]{
                        orderSkuVo.getStatus(), now,
                        orderSkuVo.getOrderSkuId(), now, now
                });
            } else {
                for (String orderSkuId : orderVo.getOrderSkuVoIds()) {
                    //订单款式状态修改
                    GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
                    if (2 == orderSkuVo.getSkuType()) {// 券类商品-校验发放的券是否已使用
                        // 券类商品默认一个商品对应一个券，下单只可购买一张
                        String ucKey = CandyRedisConst.BASIC_USER_COUPON.concat(orderVo.getUserId());
                        List<CandyUserCouponBasicDto> vos = (List<CandyUserCouponBasicDto>) redisUtils.get(ucKey);
                        int idx = IntStream.range(0, vos.size()).filter(i -> vos.get(i).getUcouponId().equals(orderSkuVo.getOrderSkuId())).findFirst().orElse(-1);
                        if (-1 != idx) {
                            CandyUserCouponBasicDto basicDto = vos.get(idx);
                            if (5 == basicDto.getState()) {// 券状态为'5-已使用'，则不可退款
                                return ResponseDto.failure("券已使用，不可申请");
                            }
                            basicDto.setState(2);// 置为'2-无效'，防止用户在后台审核过程中使用券，造成券已使用，订单也退款
                            vos.set(idx, basicDto);
                            redisUtils.redisUtil.set(ucKey, vos);
                            updateCandyUserCouponObjs.add(new Object[]{basicDto.getState(), orderVo.getUserId(), now, basicDto.getUcouponId()});
                        } else {
                            log.warn("券类商品订单申请退款，未找到对应券[orderSkuId={},uid={}]", orderSkuVo.getOrderSkuId(), orderVo.getUserId());
                        }
                    }
                    orderSkuVo.setStatus(GoblinStatusConst.Status.ORDER_STATUS_61.getValue());
                    GoblinBackOrderSkuVo backOrderSkuVo = GoblinBackOrderSkuVo.getNew();
                    backOrderSkuVo.setOrderSkuId(orderSkuId);
                    backOrderSkuVo.setSpuId(orderSkuVo.getSpuId());
                    backOrderSkuVo.setSpuName(orderSkuVo.getSpuName());
                    backOrderSkuVo.setSkuId(orderSkuVo.getSkuId());
                    backOrderSkuVo.setSkuName(orderSkuVo.getSkuName());
                    backOrderSkuVo.setSkuSpecs(orderSkuVo.getSkuSpecs());
                    backOrderSkuVo.setSkuPic(orderSkuVo.getSkuImage());
                    backOrderSkuVo.setRefundPrice(orderSkuVo.getSkuPriceActual());
                    backOrderSkuVo.setCreatedAt(nowStr);
                    backOrderSkuVo.setSkuType(orderSkuVo.getSkuType());
                    orderSkuVoList.add(backOrderSkuVo);
                    backOrderLog(orderVo, orderSkuVo, now);
                    //redis
                    redisUtils.setGoblinOrderSku(orderSkuVo.getOrderSkuId(), orderSkuVo);
                    //mongo
                    mongoUtils.updateGoblinOrderSkuVo(orderSkuVo.getOrderSkuId(), orderSkuVo);
                    orderSkuStatus.add(new Object[]{
                            orderSkuVo.getStatus(), now,
                            orderSkuVo.getOrderSkuId(), now, now
                    });
                }
            }
        } else {
            return ResponseDto.failure("不可申请");
        }
        vo.setBackOrderSkuVos(orderSkuVoList);
        //添加日志
        GoblinBackOrderLog backOrderLog = initBackLog(param.getOrderId(), uid, now);
        backOrderLog.setStatus(GoblinStatusConst.Status.ORDER_LOG_STATUS_21.getValue());
        backOrderLog.setOperationType(GoblinStatusConst.Type.OPERATION_TYPE_1.getValue());
        backOrderLog.setMessage("用户发起发起：" + JsonUtils.toJson(param));
        //redis
        redisUtils.setBackOrderVo(backOrder.getBackOrderId(), vo);
        redisUtils.setGoblinOrder(orderVo.getOrderId(), orderVo);
        redisUtils.addBackOrderByOrderId(orderVo.getOrderId(), backOrder.getBackOrderId());
        //mongo
        mongoUtils.insertGoblinBackOrderVo(vo);
        mongoUtils.updateGoblinStoreOrderVo(orderVo.getOrderId(), orderVo);
        //mysql
        applyRefund.add(new Object[]{
                backOrder.getBackOrderId(), backOrder.getBackCode(), backOrder.getOrderId(),
                backOrder.getOrderCode(), backOrder.getStoreId(), backOrder.getUserId(),
                backOrder.getSkuIdNums(), backOrder.getType(), backOrder.getReason(),
                backOrder.getDescribes(), backOrder.getRealBackPrice(), backOrder.getBackPriceExpress(), backOrder.getStatus(),
                backOrder.getLogisCompanyName(), backOrder.getMailNo(), backOrder.getPics(), backOrder.getCreatedAt()
        });
        //添加日志
        refundLog.add(new Object[]{
                backOrderLog.getBackOrderLogId(), backOrderLog.getBackOrderId(), backOrderLog.getOperationType(),
                backOrderLog.getMessage(), backOrderLog.getOperationName(), backOrderLog.getStatus(), now
        });
        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.GOBLIN_USER_ORDER_OPERA.getKey(), SqlMapping.gets(sqls, applyRefund, orderStatus, orderSkuStatus, refundLog, updateCandyUserCouponObjs));
        return ResponseDto.success();
    }

    @Override
    public ResponseDto<Boolean> againRefund(GoblinAppOrderRefundParam param) {
        LinkedList<String> sqls = CollectionUtil.linkedListString();
        sqls.add(SqlMapping.get("goblin_order.user.againRefund"));
        sqls.add(SqlMapping.get("goblin_order.store.refundLog"));

        LinkedList<Object[]> applyRefund = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> refundLog = CollectionUtil.linkedListObjectArr();

        String uid = CurrentUtil.getCurrentUid();
        LocalDateTime now = LocalDateTime.now();
        GoblinBackOrderVo backOrder = redisUtils.getBackOrderVo(param.getOrderBackId());
        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(backOrder.getOrderId());
        if (!orderVo.getUserId().equals(uid) || !backOrder.getStatus().equals(GoblinStatusConst.Status.ORDER_BACK_STATUS_3.getValue())) {
            return ResponseDto.failure("无权操作");
        }
        if (!(orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_2.getValue() ||
                orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_4.getValue())) {
            return ResponseDto.failure("不可操作");
        }
        //判断7天
        LocalDateTime canRefundTime = getCanRefundTime(orderVo);
        if (canRefundTime == null) {
            return ResponseDto.failure("申请失败");
        } else {
            if (LocalDateTime.now().isAfter(canRefundTime)) {
                return ResponseDto.failure("申请失败");
            }
        }
        backOrder.setStatus(GoblinStatusConst.Status.ORDER_BACK_STATUS_1.getValue());
        backOrder.setDescribes(param.getDescribes());
        backOrder.setPics(param.getPics());
        backOrder.setReason(param.getReason());
        backOrder.setType(param.getRefundType());
        //添加日志
        GoblinBackOrderLog backOrderLog = initBackLog(backOrder.getOrderId(), uid, now);
        backOrderLog.setStatus(GoblinStatusConst.Status.ORDER_LOG_STATUS_21.getValue());
        backOrderLog.setOperationType(GoblinStatusConst.Type.OPERATION_TYPE_1.getValue());
        backOrderLog.setMessage("用户再次发起退款：" + backOrder);
        //redis
        redisUtils.setBackOrderVo(backOrder.getBackOrderId(), backOrder);
        //mongo
        mongoUtils.updateGoblinBackOrderVo(backOrder.getBackOrderId(), backOrder);
        //mysql
        applyRefund.add(new Object[]{
                backOrder.getStatus(),
                backOrder.getDescribes(), backOrder.getPics(), backOrder.getReason(), backOrder.getType(),
                now, backOrder.getBackOrderId()
        });
        //添加日志
        refundLog.add(new Object[]{
                backOrderLog.getBackOrderLogId(), backOrderLog.getBackOrderId(), backOrderLog.getOperationType(),
                backOrderLog.getMessage(), backOrderLog.getOperationName(), backOrderLog.getStatus(), now
        });
        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.GOBLIN_USER_ORDER_OPERA.getKey(), SqlMapping.gets(sqls, applyRefund, refundLog));
        return ResponseDto.success();
    }

    @Override
    public ResponseDto<List<GoblinBackOrderVo>> refundDetails(String orderId) {
        List<GoblinBackOrderVo> vos = ObjectUtil.goblinBackOrderVoArrayList();
        List<String> backOrderList = redisUtils.getBackOrderByOrderId(orderId);
        for (String backOrderId : backOrderList) {
            GoblinBackOrderVo vo = redisUtils.getBackOrderVo(backOrderId);
            GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(vo.getOrderId());
            vo.setPayType(orderVo.getPayType());
            vos.add(vo);
        }
        return ResponseDto.success(vos);
    }

//    @Override
//    public String huiFuSync(HttpServletRequest request) {
//        try {
//            // 验签请参data
//            String responseData = request.getParameter("resp_data");
//            // 验签请参sign
//            String sign = request.getParameter("sign");
//            // 使用汇付公钥验签
////            if (!RsaUtils.verify(responseData, PUBLIC_KEY, sign)) {
////                // 验签失败处理
////                return "";
////            }
//            JSONObject dataObj = JSON.parseObject(responseData);
//            String subRespCode = dataObj.getString("sub_resp_code");
//            String reqSeqId = dataObj.getString("req_seq_id");
//            String orderMasterCode = dataObj.getString("mer_ord_id");
//            String payCode = dataObj.getString("mer_ord_id");
//            String paymentType = dataObj.getString("trans_type");
//            String paymentId = dataObj.getString("hf_seq_id");
//            String paymentAt = dataObj.getString("end_time");
//            if ("00000000".equals(subRespCode)) {
//                log.debug("SYNC PARAM = " + responseData);
//                //支付时间
//                LocalDateTime now = LocalDateTime.now();
//                String[] array = redisUtils.getMasterCode(orderMasterCode);
//                String uid = "zhengzai";
//                BigDecimal priceActual = BigDecimal.ZERO;
//                for (String orderId : array) {
//                    GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
//                    if(orderVo.getStatus()==GoblinStatusConst.Status.ORDER_STATUS_4.getValue()){
//                        continue;
//                    }
//                    uid = orderVo.getUserId();
//                    priceActual = priceActual.add(orderVo.getPriceActual());
//                    if (orderVo == null) {
//                        log.error("订单号：" + orderMasterCode + " 订单不存在");
//                        return "fail";//订单不存在
//                    }
//                    LinkedList<String> sqls = CollectionUtil.linkedListString();
//                    LinkedList<Object[]> sqlDataOrder = CollectionUtil.linkedListObjectArr();
//                    LinkedList<Object[]> sqlDataSku = CollectionUtil.linkedListObjectArr();
//                    GoblinStoreOrder storeOrder = GoblinStoreOrder.getNew();
//                    storeOrder.setPaymentType(paymentType);
//                    storeOrder.setPaymentId(paymentId);
//                    storeOrder.setPayCode(payCode);
//                    LocalDateTime payTime = LocalDateTime.parse(paymentAt, DTFYMDHMS);
//                    storeOrder.setPayTime(payTime);
//                    if (orderVo.getWriteOffCode().equals("EMPTY")) {
//                        storeOrder.setWriteOffCode(IDGenerator.getWriteOffCode());
//                    } else {
//                        storeOrder.setWriteOffCode("");
//                    }
//                    storeOrder.setStatus(GoblinStatusConst.Status.ORDER_STATUS_4.getValue());
//                    storeOrder.setUpdatedAt(now);
//                    sqls.add(SqlMapping.get("goblin_order.pay.order"));
//                    sqlDataOrder.add(new Object[]{
//                            storeOrder.getPaymentType(), storeOrder.getPaymentId(), storeOrder.getPayCode(), storeOrder.getPayTime(), storeOrder.getWriteOffCode(), storeOrder.getStatus(), storeOrder.getUpdatedAt(),
//                            orderId, now, now
//                    });
//                    sqls.add(SqlMapping.get("goblin_order.pay.sku"));
//                    List<String> skuList = orderVo.getOrderSkuVoIds();
//                    for (String orderSkuVoIds : skuList) {
//                        GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuVoIds);
//                        //增加销量
//                        redisUtils.incrSkuSaleCount(orderSkuVo.getSpuId(), orderSkuVo.getSkuId(), orderSkuVo.getNum());
//                        orderSkuVo.setStatus(GoblinStatusConst.Status.ORDER_STATUS_4.getValue());
//                        //redis
//                        redisUtils.setGoblinOrderSku(orderSkuVo.getOrderSkuId(), orderSkuVo);
//                        //mongo
//                        mongoUtils.updateGoblinOrderSkuVo(orderSkuVo.getOrderSkuId(), orderSkuVo);
//                        //mongo 添加操作日志
//                        GoblinOrderLogVo logVo = GoblinOrderLogVo.getNew();
//                        logVo.setOrderId(orderVo.getOrderId());
//                        logVo.setOrderCode(orderVo.getOrderCode());
//                        logVo.setPayCode(orderVo.getPayCode());
//                        logVo.setStoreId(orderVo.getStoreId());
//                        if (orderSkuVo.getSkuId().indexOf(GoblinStatusConst.MarketPreStatus.MARKET_PRE_ZHENGZAI.getValue()) > 0) {
//                            logVo.setOrderType("zhengzai");
//                        } else {
//                            logVo.setOrderType("order");
//                        }
//                        logVo.setSpuId(orderSkuVo.getSpuId());
//                        logVo.setSkuId(orderSkuVo.getSkuId());
//                        logVo.setSkuPriceActual(orderSkuVo.getSkuPriceActual().multiply(new BigDecimal(100)).longValue());
//                        logVo.setStatus(GoblinStatusConst.Status.ORDER_LOG_STATUS_11.getValue());
//                        logVo.setRemark(GoblinStatusConst.Status.ORDER_LOG_STATUS_11.getDesc());
//                        logVo.setOperationId(uid);
//                        logVo.setOperationName(orderVo.getUserName());
//                        logVo.setOperationType(GoblinStatusConst.Type.OPERATION_TYPE_1.getValue());
//                        logVo.setCreatedAt(LocalDateTime.now());
//                        mongoUtils.insertGoblinOrderLogVo(logVo);
//                        //mysql
//                        sqlDataSku.add(new Object[]{
//                                orderSkuVo.getStatus(), now,
//                                orderSkuVo.getOrderSkuId(), now, now
//                        });
//                    }
//                    //redis
//                    orderVo.setPayCode(storeOrder.getPayCode());
//                    orderVo.setPayTime(paymentAt);
//                    orderVo.setWriteOffCode(storeOrder.getWriteOffCode());
//                    orderVo.setStatus(storeOrder.getStatus());
//                    orderVo.setPaymentId(paymentId);
//                    orderVo.setPaymentType(paymentType);
//                    orderVo.setOrderSkuVoIds(skuList);
//                    redisUtils.setGoblinOrder(orderId, orderVo);
//                    redisUtils.setOffCode(orderVo.getWriteOffCode(), orderVo.getMasterOrderCode());
//                    //删除未支付订单
//                    redisUtils.removeGoblinOrder(orderVo.getRandomKey() + "", orderId);
//                    //mongo
//                    mongoUtils.updateGoblinStoreOrderVo(orderId, orderVo);
//                    //mysql
//                    queueUtils.sendMsgByRedis(MQConst.GoblinQueue.GOBLIN_ORDER_CREATE_PAY.getKey(),
//                            SqlMapping.gets(sqls, sqlDataOrder, sqlDataSku));
//                }
//                //加分
//                if (noZhengzaiOrder(uid)) {
//                    orderUtils.doTask(uid, priceActual);
//                }
//            } else {
//                // 业务处理失败
//                log.info("处理失败");
//            }
//            return "RECV_ORD_ID_" + reqSeqId;
//        } catch (Exception e) {
//            log.info("异步回调开始，参数，request={},异常={}", request, e);
//            e.printStackTrace();
//        }
//        return "";
//    }

    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 void backOrderLog(GoblinStoreOrderVo orderVo, GoblinOrderSkuVo orderSkuVo, LocalDateTime now) {
        //操作日志vo
        GoblinOrderLogVo logVo = GoblinOrderLogVo.getNew();
        logVo.setOrderId(orderVo.getOrderId());
        logVo.setOrderCode(orderVo.getOrderCode());
        logVo.setPayCode(orderVo.getPayCode());
        if (orderSkuVo.getSkuId().indexOf(GoblinStatusConst.MarketPreStatus.MARKET_PRE_ZHENGZAI.getValue()) > 0) {
            logVo.setOrderType("zhengzai");
        } else {
            logVo.setOrderType("order");
        }
        logVo.setStoreId(orderVo.getStoreId());
        logVo.setSpuId(orderSkuVo.getSpuId());
        logVo.setSpuName(orderSkuVo.getSpuName());
        logVo.setSkuId(orderSkuVo.getSkuId());
        logVo.setSkuPriceActual(orderSkuVo.getSkuPriceActual().multiply(BigDecimal.valueOf(100)).negate().longValue());
        logVo.setStatus(GoblinStatusConst.Status.ORDER_LOG_STATUS_21.getValue());
        logVo.setRemark("申请退款,orderSkuVoId=" + orderSkuVo.getOrderSkuId());
        logVo.setOperationId(orderVo.getUserId());
        logVo.setOperationType(GoblinStatusConst.Type.OPERATION_TYPE_2.getValue());
        logVo.setCreatedAt(now);
        mongoUtils.insertGoblinOrderLogVo(logVo);
    }

    @Override
    public ResponseDto<List<GoblinMailVo>> getMail(String orderId, String mailId) {
        List<GoblinMailVo> voList = redisUtils.getGoblinMail(orderId);
        for (GoblinMailVo vo : voList) {
            if (mailId.equals(vo.getMailId())) {
                List<GoblinOrderSkuVo> orderSkuVos = ObjectUtil.getGoblinOrderSkuVoArrayList();
                for (String orderSkuId : vo.getOrderSkuVoIds()) {
                    GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
                    orderSkuVos.add(orderSkuVo);
                }
                vo.setOrderSkuVos(orderSkuVos);
            }
        }
        return ResponseDto.success(voList);
    }

    //获取 订单剩余可支付时间[S]
    private long getRestTime(GoblinStoreOrderVo orderVo) {
        long restTime = 0L;
        int time = orderVo.getPayCountdownMinute();
        if (orderVo.getMarketType() != null && orderVo.getMarketType().equals(GoblinStatusConst.MarketPreStatus.MARKET_PRE_ZHENGZAI.getValue())) {
            time = 0;
        }
        if (orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_0.getValue()) {
            try {
                Date OverdueAt = DateUtil.addMin(DateUtil.parse(orderVo.getCreatedAt(), "yyyy-MM-dd HH:mm:ss"), time);
                restTime = DateUtil.intervalSeconds(
                        OverdueAt,
                        DateUtil.parse(DateUtil.getNowTime(), "yyyy-MM-dd HH:mm:ss")
                );
                if (restTime <= 0L) {
                    restTime = 0L;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return restTime;
    }

    //获取 可申请退款时间
    private LocalDateTime getCanRefundTime(GoblinStoreOrderVo orderVo) {
        LocalDateTime canRefundTimeDateTime = null;
        if (orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_2.getValue() || orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_4.getValue()) {
            try {
                canRefundTimeDateTime = LocalDateTime.parse(orderVo.getPayTime(), DTF_YMD_HMS).plusDays(7);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return canRefundTimeDateTime;
    }

    private boolean noZhengzaiOrder(String uid) {
        return !uid.equals("zhengzai");
    }
}
