package com.liquidnet.service.order.utils;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.type.TypeReference;
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.param.BackCouponParam;
import com.liquidnet.service.candy.vo.CandyUseResultVo;
import com.liquidnet.service.goblin.constant.GoblinStatusConst;
import com.liquidnet.service.goblin.dto.GoblinQueueBizIntegralDto;
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.GoblinOrderSku;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@Component
@Slf4j
public class GoblinOrderUtils {

    @Value("${liquidnet.service.candy.url}")
    private String candyUrl;
    @Value("${liquidnet.service.order.url-pay.goblinRefundUrl}")
    private String synUrl;
    @Value("${liquidnet.service.dragon.urls.refundApply}")
    private String refundApply;

    @Autowired
    QueueUtils queueUtils;
    @Autowired
    GoblinRedisUtils redisUtils;
    @Autowired
    GoblinMongoUtils goblinMongoUtils;

    //判断 数量限购
    public String judgeOrderLimit(String uid, String skuId, int number, int limitCount) {
        int buyCount = redisUtils.incrSkuCountByUid(uid, skuId, number);
        if (buyCount > limitCount) {
//            redisUtils.decrSkuCountByUid(uid, skuId, number);
            return "已超出限购数量";
        } else {
            return "";
        }
    }

    //判断指定人群购买
    public Boolean judgeOrderRose(Boolean isMember, String skuId, String mobile, int buyFactor) {
        Boolean result = false;
        switch (buyFactor) {
            case 0:
                result = true;
                break;
            case 1:
                result = isMember;
                break;
            case 2:
                result = redisUtils.getSkuCanBuyByUid(mobile, skuId);
                break;
        }
        return result;
    }

    /**
     * 使用优惠券
     *
     * @param uCouponId  券id
     * @param content    消费内容
     * @param totalPrice 订单总价
     * @return
     */
    public HashMap<String, Object> useCoupon(String uCouponId, String content, BigDecimal totalPrice, String spuId, String uid, List<GoblinOrderSku> goblinOrderSkuList) {
        HashMap<String, Object> hashMap = CollectionUtil.mapStringObject();
        try {
            MultiValueMap<String, String> params = CollectionUtil.linkedMultiValueMapStringString();
            params.add("uCouponId", uCouponId);
            params.add("content", content);
            params.add("totalPrice", totalPrice.toString());
            params.add("goodId", spuId);
            params.add("performanceId", "null");
            params.add("timeId", "null");
            params.add("ticketId", "null");
            params.add("uid", uid);
            MultiValueMap<String, String> header = CollectionUtil.linkedMultiValueMapStringString();
            header.add("Authorization", "Bearer " + CurrentUtil.getToken());
            header.add("Accept", "application/json;charset=UTF-8");
            log.debug("url=" + candyUrl + "/candy-coupon/use");
            String returnData = HttpUtil.post(candyUrl + "/candy-coupon/use", params, header);
            ResponseDto<CandyUseResultVo> innerReturnVo = JsonUtils.fromJson(returnData, new TypeReference<ResponseDto<CandyUseResultVo>>() {
            });
            CandyUseResultVo candyUseResultVo = innerReturnVo.getData();
            Integer type = candyUseResultVo.getCouType();
            List<String> targetList = candyUseResultVo.getTargetIds();
            BigDecimal fullValue = candyUseResultVo.getFullValue();
            BigDecimal value = candyUseResultVo.getValue();
            BigDecimal voucher = BigDecimal.ZERO;
            BigDecimal targetPrice = BigDecimal.ZERO;
            switch (type) {
                case -1:
                    voucher = BigDecimal.valueOf(-1);
                    break;
                case 1:
                    if (targetList.size() == 0) {
                        targetPrice = totalPrice;
                    } else {
                        for (String targetId : targetList) {
                            for (GoblinOrderSku skuOrderVo : goblinOrderSkuList) {
                                String orderVoSpuId = skuOrderVo.getSpuId();
                                String pre = GoblinStatusConst.MarketPreStatus.getPre(orderVoSpuId);
                                if (pre != null) {
                                    orderVoSpuId = orderVoSpuId.split(pre)[0];
                                }
                                if (targetId.equals(orderVoSpuId)) {
                                    targetPrice = targetPrice.add(skuOrderVo.getSkuPriceActual());
                                }
                            }
                        }
                    }
                    if (targetPrice.compareTo(value) >= 0) {
                        voucher = voucher.add(value);
                    } else {
                        voucher = voucher.add(targetPrice);
                    }
                    break;
                case 2://满减
                    if (targetList.size() == 0) {
                        targetPrice = totalPrice;
                    } else {
                        for (String targetId : targetList) {
                            for (GoblinOrderSku skuOrderVo : goblinOrderSkuList) {
                                String orderVoSpuId = skuOrderVo.getSpuId();
                                String pre = GoblinStatusConst.MarketPreStatus.getPre(orderVoSpuId);
                                if (pre != null) {
                                    orderVoSpuId = orderVoSpuId.split(pre)[0];
                                }
                                if (targetId.equals(orderVoSpuId)) {
                                    targetPrice = targetPrice.add(skuOrderVo.getSkuPriceActual());
                                }
                            }
                        }
                    }
                    if (fullValue.compareTo(targetPrice) <= 0) {
                        voucher = voucher.add(value);
                    } else {
                        backCoupon(uCouponId, uid);
                        hashMap.put("type", -1);
                        hashMap.put("voucher", BigDecimal.ZERO);
                        return hashMap;
                    }
                    break;
                case 3:
                    voucher = voucher.add(totalPrice);
                    break;
                case 4://折扣
                    if (targetList.size() == 0) {
                        targetPrice = totalPrice;
                    } else {
                        for (String targetId : targetList) {
                            for (GoblinOrderSku skuOrderVo : goblinOrderSkuList) {
                                if (targetId.equals(skuOrderVo.getSpuId())) {
                                    targetPrice = targetPrice.add(skuOrderVo.getSkuPriceActual());
                                }
                            }
                        }
                    }
                    voucher = targetPrice.subtract(targetPrice.multiply(value));
                    break;
                default:
                    voucher = BigDecimal.ZERO;
                    break;
            }
            hashMap.put("spuIds", targetList);
            hashMap.put("type", type);
            hashMap.put("voucher", voucher.setScale(2, BigDecimal.ROUND_HALF_UP));
            return hashMap;
        } catch (Exception e) {
            log.error("用券ERROR:{}", e);
            return null;
        }
    }

    public void backCoupon(String uCouponId, String uid) {
        try {
            BackCouponParam param = BackCouponParam.getNew();
            param.setuCouponIds(uCouponId);
            param.setUid(uid);

            MultiValueMap<String, String> header = CollectionUtil.linkedMultiValueMapStringString();
            header.add("Authorization", "Bearer " + CurrentUtil.getToken());
            header.add("Accept", "application/json;charset=UTF-8");
            ArrayList<BackCouponParam> params = new ArrayList();
            params.add(param);
            String jsonString = JSON.toJSONString(params);
            String returnData = HttpUtil.postRaw(candyUrl + "/candy-coupon/useBack", jsonString, header);
        } catch (Exception e) {
            log.error("回退券ERROR:{}", e);
        }
    }

    public void integral(String uid, BigDecimal price, String content, int type) {
        if (price.intValue() > 0) {
            GoblinQueueBizIntegralDto goblinQueueBizIntegralDto = GoblinQueueBizIntegralDto.getNew();
            goblinQueueBizIntegralDto.setUid(uid);
            goblinQueueBizIntegralDto.setScore(price);
            goblinQueueBizIntegralDto.setContent(content);
            goblinQueueBizIntegralDto.setType(type);
            queueUtils.sendMsgByRedis(MQConst.GoblinQueue.BIZ_INTEGRAL.getKey(), goblinQueueBizIntegralDto.toJson());
        }
    }

    public GoblinUseResultVo useStoreCoupon(String ucouponId, String content, BigDecimal totalPrice, List<GoblinOrderSku> goblinOrderSkuList, String uid) {
        try {
            List<GoblinUserCouponVo> voList = redisUtils.getUserCouponVos(uid);
            GoblinUseResultVo returnVo = GoblinUseResultVo.getNew();
            returnVo.setValue(BigDecimal.ZERO);
            returnVo.setCouType("-1");
            LocalDateTime now = LocalDateTime.now();
            List<String> spuIds = CollectionUtil.linkedListString();
            for (GoblinUserCouponVo vo : voList) {
                if (vo.getUcouponId().equals(ucouponId) && vo.getDuedAt().isAfter(now)) {
                    //判断券状态 和 触发金额
                    if ((vo.getState().equals(1))) {
                        if (vo.getUseScope().equals("0") && vo.getTriggers().compareTo(totalPrice) <= 0) {
                            if (vo.getType().equals("1")) {//代金券
                                returnVo.setValue(vo.getValFace());
                                returnVo.setCouType(vo.getType());
                            } else if (vo.getType().equals("2")) {//折扣
                                BigDecimal tempPrice = totalPrice.subtract(totalPrice.multiply(vo.getDiscount()).setScale(2, BigDecimal.ROUND_HALF_UP));
                                if (tempPrice.compareTo(vo.getDeduction()) > 0) {
                                    tempPrice = vo.getDeduction();
                                }
                                returnVo.setValue(tempPrice);
                                returnVo.setCouType(vo.getType());
                            } else if (vo.getType().equals("3") && vo.getTriggers().compareTo(totalPrice) <= 0) {//满减
                                returnVo.setValue(vo.getValMinus());
                                returnVo.setCouType(vo.getType());
                            }
                            vo.setState(5);
                            vo.setUsedFor(content);
                            goblinMongoUtils.changeCouponVos(vo.getUcouponId(), vo);
                            queueUtils.sendMsgByRedis(MQConst.GoblinQueue.SQL_COUPON.getKey(),
                                    SqlMapping.get("goblin_user_coupon.updateState", vo.getState(), vo.getUsedFor(), LocalDateTime.now(), vo.getUcouponId()));
                            break;
                        } else {
                            spuIds = redisUtils.getStoreCouponSpuIds(vo.getStoreCouponId());
                            if (spuIds == null || spuIds.size() == 0) {
                                continue;
                            }
                            //判断是否在可用商品内
                            BigDecimal contentPrice = BigDecimal.ZERO;
                            for (String item : spuIds) {
                                for (GoblinOrderSku param : goblinOrderSkuList) {
                                    String spuId = param.getSpuId();
                                    String pre = GoblinStatusConst.MarketPreStatus.getPre(spuId);
                                    if (pre != null) {
                                        spuId = spuId.split(pre)[0];
                                    }
                                    if (spuId.equals(item)) {
                                        contentPrice = contentPrice.add(param.getSkuPriceActual());
                                    }
                                }
                            }
                            if (vo.getTriggers().compareTo(contentPrice) <= 0) {
                                if (vo.getType().equals("1")) {//代金券
                                    if (vo.getValFace().compareTo(contentPrice) > 0) {
                                        returnVo.setValue(contentPrice);
                                    } else {
                                        returnVo.setValue(vo.getValFace());
                                    }
                                    returnVo.setCouType(vo.getType());
                                } else if (vo.getType().equals("2")) {//折扣
                                    BigDecimal tempPrice = contentPrice.subtract(contentPrice.multiply(vo.getDiscount()).setScale(2, BigDecimal.ROUND_HALF_UP));
                                    if (tempPrice.compareTo(vo.getDeduction()) > 0) {
                                        tempPrice = vo.getDeduction();
                                    }
                                    returnVo.setValue(tempPrice);
                                    returnVo.setCouType(vo.getType());
                                } else if (vo.getType().equals("3")) {//满减
                                    if (vo.getValMinus().compareTo(contentPrice) > 0) {
                                        returnVo.setValue(contentPrice);
                                    } else {
                                        returnVo.setValue(vo.getValMinus());
                                    }
                                    returnVo.setCouType(vo.getType());
                                }
                                vo.setState(5);
                                vo.setUsedFor(content);
                                goblinMongoUtils.changeCouponVos(vo.getUcouponId(), vo);
                                queueUtils.sendMsgByRedis(MQConst.GoblinQueue.SQL_COUPON.getKey(),
                                        SqlMapping.get("goblin_user_coupon.updateState", vo.getState(), vo.getUsedFor(), LocalDateTime.now(), vo.getUcouponId()));
                            }

                        }
                    }
                    break;
                }
            }
            if (!returnVo.getCouType().equals("-1")) {
                redisUtils.setUserCouponVos(uid, voList);
            }
            returnVo.setSpuIds(spuIds);
            return returnVo;
        } catch (Exception e) {
            log.error("店铺券错误:{}", e);
            return null;
        }
    }

    public Boolean backStoreCoupon(List<com.liquidnet.service.goblin.param.BackCouponParam> params) {
        try {
            for (com.liquidnet.service.goblin.param.BackCouponParam item : params) {
                List<GoblinUserCouponVo> voList = redisUtils.getUserCouponVos(item.getUid());
                for (GoblinUserCouponVo vo : voList) {
                    if (vo.getUcouponId().equals(item.getuCouponIds())) {
                        if (LocalDateTime.now().isBefore(vo.getDuedAt())) {
                            vo.setState(1);
                            vo.setUsedFor("");
                            redisUtils.setUserCouponVos(item.getUid(), voList);
                            goblinMongoUtils.changeCouponVos(vo.getUcouponId(), vo);
                            queueUtils.sendMsgByRedis(MQConst.GoblinQueue.SQL_COUPON.getKey(),
                                    SqlMapping.get("goblin_user_coupon.updateState", vo.getState(), vo.getUsedFor(), LocalDateTime.now(), vo.getUcouponId()));
                        }
                        break;
                    }
                }
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public Integer getMember(String uid) {
        return redisUtils.getMember(uid);
    }


    //超时支付自动退款
    public Boolean refundOrderSku(String orderId, String paymentId, String paymentType) {
        int autoSize = redisUtils.getBackOrderByOrderId(orderId).size();
        if (autoSize > 0) {
            return true;
        }
        String uid = CurrentUtil.getCurrentUid();
        LocalDateTime now = LocalDateTime.now();
        String nowStr = DateUtil.getNowTime();
        List<GoblinBackOrderSkuVo> orderSkuVoList = ObjectUtil.goblinBackOrderSkuVoArrayList();
        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
        BigDecimal refundPrice = BigDecimal.ZERO;
        for (String orderSkuIdItem : orderVo.getOrderSkuVoIds()) {
            GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuIdItem);
            GoblinBackOrderSkuVo backOrderSkuVo = GoblinBackOrderSkuVo.getNew();
            backOrderSkuVo.setOrderSkuId(orderSkuIdItem);
            backOrderSkuVo.setSpuId(orderSkuVo.getSpuId());
            backOrderSkuVo.setSpuName(orderSkuVo.getSpuName());
            backOrderSkuVo.setSkuId(orderSkuVo.getSkuId());
            backOrderSkuVo.setSkuName(orderSkuVo.getSkuName());
            backOrderSkuVo.setRefundPrice(orderSkuVo.getSkuPriceActual());
            backOrderSkuVo.setSkuSpecs(orderSkuVo.getSkuSpecs());
            backOrderSkuVo.setCreatedAt(nowStr);
            backOrderSkuVo.setSkuPic(orderSkuVo.getSkuImage());
            orderSkuVoList.add(backOrderSkuVo);
            refundPrice = refundPrice.add(orderSkuVo.getSkuPriceActual().subtract(orderSkuVo.getPriceRefund()));
        }
        //记录退款单
        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_10.getDesc());
        goblinBackOrder.setDescribes("超时支付自动退款");
        refundPrice = refundPrice.add(orderVo.getPriceExpress());
        goblinBackOrder.setRealBackPrice(refundPrice);
        goblinBackOrder.setStatus(GoblinStatusConst.Status.ORDER_BACK_STATUS_0.getValue());
        goblinBackOrder.setAuditAt(now);
        goblinBackOrder.setCreatedAt(now);
        GoblinBackOrderVo backOrderVo = GoblinBackOrderVo.getNew().copy(goblinBackOrder);
        backOrderVo.setCreatedAt(nowStr);
        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("商户发起[自动退款]：orderId=[" + orderId + "],refundPrice=[" + refundPrice + "],[refundCode=" + refundCode + "]");
        //调用退款
        orderVo.setPaymentId(paymentId);
        orderVo.setPaymentType(paymentType);
        String returnString = initRefund(orderVo, refundPrice, refundCode);
        HashMap hashMapResult = JsonUtils.fromJson(returnString, HashMap.class);
        Boolean success = (Boolean) hashMapResult.get("success");
        String message = (String) hashMapResult.get("message");
        if (!success) {
            if (!(backOrderVo.getStatus() == GoblinStatusConst.Status.ORDER_BACK_STATUS_8.getValue() || backOrderVo.getStatus() == GoblinStatusConst.Status.ORDER_BACK_STATUS_2.getValue())) {
                backOrderVo.setStatus(GoblinStatusConst.Status.ORDER_BACK_STATUS_10.getValue());
                backOrderVo.setErrorReason(backOrderVo.getErrorReason() + ",失败原因：" + message);
                log.error("REFUND DATA = " + returnString);
            }
        }
        //redis
        redisUtils.setBackOrderVo(backOrderVo.getBackOrderId(), backOrderVo);
        redisUtils.addBackOrderByOrderId(orderVo.getOrderId(), backOrderVo.getBackOrderId());
        //mongo
        goblinMongoUtils.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(), goblinBackOrder.getErrorReason()
                )
        );
        //添加日志
        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 true;
        } else {
            log.error("退款失败:" + message);
            return false;
        }
    }

    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));
        BigDecimal totalPrice = BigDecimal.ZERO;
        totalPrice = totalPrice.add(price);
        params.add("priceTotal", String.valueOf(totalPrice));
        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;
    }

    //订单异常处理
    public ResponseDto<GoblinPayInnerResultVo> orderException(List<String> skuAndPreListAndNumber, List<String> platformCodeList, List<String> storeCodeList, String uid, String message) {
        long time3 = System.currentTimeMillis();
        //回顾限购 回滚库存
        for (String item : skuAndPreListAndNumber) {
            String[] array = item.split(",");
            String skuId = array[0];
            String pre = array[1];
            int number = Integer.parseInt(array[2]);
            redisUtils.incrSkuStock(pre, skuId, number);
            if (noZhengzaiOrder(uid)) {
                redisUtils.decrSkuCountByUid(uid, skuId, number);
            }
        }
        //回退平台券
        for (String platformCode : platformCodeList) {
            backCoupon(platformCode, uid);
        }
        //回退店铺券
        List<com.liquidnet.service.goblin.param.BackCouponParam> params = ObjectUtil.getBackCouponParam();
        for (String storeCode : storeCodeList) {
            com.liquidnet.service.goblin.param.BackCouponParam backCouponParam = com.liquidnet.service.goblin.param.BackCouponParam.getNew();
            backCouponParam.setuCouponIds(storeCode);
            backCouponParam.setUid(uid);
            params.add(backCouponParam);
        }
        if (params.size() > 0) {
            backStoreCoupon(params);
        }
        log.info("回滚逻辑 " + (System.currentTimeMillis() - time3) + "ms");
        if (message == null && !message.equals("")) {
            return ResponseDto.failure(ErrorMapping.get("20018"));//乱七八糟异常
        } else {
            return ResponseDto.failure(message);//乱七八糟异常
        }
    }

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