package com.liquidnet.service.order.utils;

import com.fasterxml.jackson.core.type.TypeReference;
import com.liquidnet.common.cache.redis.util.RedisUtil;
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.candy.vo.CandyUseResultVo;
import com.liquidnet.service.goblin.constant.GoblinRedisConst;
import com.liquidnet.service.goblin.constant.GoblinStatusConst;
import com.liquidnet.service.goblin.dto.vo.GoblinNftOrderCallBackVo;
import com.liquidnet.service.goblin.dto.vo.GoblinNftOrderVo;
import com.liquidnet.service.goblin.dto.vo.GoblinUseResultVo;
import com.liquidnet.service.goblin.dto.vo.GoblinUserCouponVo;
import com.liquidnet.service.goblin.entity.GoblinNftOrderRefund;
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.HashMap;
import java.util.List;
import java.util.Objects;

@Component
@Slf4j
public class GoblinNftOrderUtils {

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

    @Autowired
    private QueueUtils queueUtils;
    @Autowired
    private GoblinRedisUtils goblinRedisUtils;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private GoblinMongoUtils goblinMongoUtils;
    @Autowired
    private GoblinOrderUtils goblinOrderUtils;

    // 库存
    public int decrSkuStock(String skuId, Integer stock) {
        String redisKey = GoblinRedisConst.REAL_STOCK_SKU.concat(skuId);
        return (int) redisUtil.decr(redisKey, stock);
    }

    public int incrSkuStock(String skuId, Integer stock) {
        String redisKey = GoblinRedisConst.REAL_STOCK_SKU.concat(skuId);
        return (int) redisUtil.incr(redisKey, stock);
    }

    // 是否是会员
    public boolean isVipMember(String uid) {
        Integer member = goblinRedisUtils.getMember(uid);
        if (null == member) {
            return false;
        } else {
            return true;
        }
    }

    // 订单详情vo
    public void setNftOrder(GoblinNftOrderVo vo) {
        String redisKey = GoblinRedisConst.REDIS_GOBLIN_NFT_ORDER_INFO.concat(vo.getOrderId());
        redisUtil.set(redisKey, vo);
    }

    // 获取 订单详情vo
    public GoblinNftOrderVo getNftOrder(String orderId) {
        String redisKey = GoblinRedisConst.REDIS_GOBLIN_NFT_ORDER_INFO.concat(orderId);
        Object obj = redisUtil.get(redisKey);
        if (obj == null) {
            return null;
        } else {
            return (GoblinNftOrderVo) obj;
        }
    }

    // 添加 订单id列表
    public void addNftOrderList(String uid, String orderId) {
        String redisKey = GoblinRedisConst.REDIS_GOBLIN_NFT_ORDER_USER_ID_LIST.concat(uid);
        List<String> list = getNftOrderList(uid);
        if (list.size() >= 40) {
            list.remove(0);
            list.add(orderId);
        } else {
            list.add(orderId);
        }
        redisUtil.set(redisKey, list);
    }

    // 获取 订单id列表
    public List<String> getNftOrderList(String uid) {
        String redisKey = GoblinRedisConst.REDIS_GOBLIN_NFT_ORDER_USER_ID_LIST.concat(uid);
        Object obj = redisUtil.get(redisKey);
        if (obj == null) {
            return CollectionUtil.arrayListString();
        } else {
            return (List<String>) obj;
        }
    }

    // 退款订单vo
    public void setBackOrderVo(GoblinNftOrderCallBackVo vo) {
        String redisKey = GoblinRedisConst.REDIS_GOBLIN_NFT_ORDER_REFUND_INFO.concat(vo.getOrderRefundId());
        redisUtil.set(redisKey, vo);
    }

    /**
     * 使用平台优惠券
     *
     * @param uCouponId  券id
     * @param content    消费内容
     * @param totalPrice 订单总价
     * @param spuId      spuId
     * @param uid        uid
     * @return
     */
    public HashMap<String, Object> useCoupon(String uCouponId, String content, BigDecimal totalPrice, String spuId, String uid) {
        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");

            String returnData = HttpUtil.post(candyUrl.concat("/candy-coupon/use"), params, header);
            ResponseDto<CandyUseResultVo> useResultVo = JsonUtils.fromJson(returnData, new TypeReference<ResponseDto<CandyUseResultVo>>() {
            });
            CandyUseResultVo candyUseResultVo = useResultVo.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) {// 券类型[-1-不可用 | 1-代金券｜2-满减券｜3-兑换券｜4-折扣券|101-优先券]
                case -1:
                    voucher = BigDecimal.valueOf(-1);
                    break;
                case 1:
                    if (targetList.size() == 0) {
                        targetPrice = totalPrice;
                    } else {
                        for (String targetId : targetList) {
                            if (targetId.equals(spuId)) {
                                targetPrice = totalPrice;
                            }
                        }
                    }
                    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) {
                            if (targetId.equals(spuId)) {
                                targetPrice = totalPrice;
                            }
                        }
                    }
                    if (fullValue.compareTo(targetPrice) <= 0) {
                        voucher = voucher.add(value);
                    } else {
                        goblinOrderUtils.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) {
                            if (targetId.equals(spuId)) {
                                targetPrice = totalPrice;
                            }
                        }
                    }
                    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;
        }
    }

    /**
     * 使用店铺优惠券
     *
     * @param uCouponId  券id
     * @param content    消费内容
     * @param totalPrice 订单总价
     * @param spuId      spuId
     * @param uid        uid
     * @return
     */
    public GoblinUseResultVo useStoreCoupon(String uCouponId, String content, BigDecimal totalPrice, String spuId, String uid) {
        try {
            List<GoblinUserCouponVo> voList = goblinRedisUtils.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 = goblinRedisUtils.getStoreCouponSpuIds(vo.getStoreCouponId());
                            if (spuIds == null || spuIds.size() == 0) {
                                continue;
                            }
                            //判断是否在可用商品内
                            BigDecimal contentPrice = BigDecimal.ZERO;
                            for (String item : spuIds) {
                                if (spuId.equals(item)) {
                                    contentPrice = totalPrice;
                                }
                            }
                            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")) {
                goblinRedisUtils.setUserCouponVos(uid, voList);
            }
            returnVo.setSpuIds(spuIds);
            return returnVo;
        } catch (Exception e) {
            log.error("店铺券错误:{}", e);
            return null;
        }
    }

    //超时支付自动退款
    public Boolean refundOrderSku(String orderId, String paymentId, String paymentType) {
        String uid = CurrentUtil.getCurrentUid();
        LocalDateTime now = LocalDateTime.now();
        String nowStr = DateUtil.getNowTime();
        GoblinNftOrderVo NftOrder = getNftOrder(orderId);
        BigDecimal refundPrice = NftOrder.getPriceActual();
        //记录退款单
        String refundCode = IDGenerator.storeRefundCode(NftOrder.getOrderCode());
        GoblinNftOrderRefund nftBackOrder = GoblinNftOrderRefund.getNew();
        nftBackOrder.setOrderRefundId(IDGenerator.nextTimeId2());
        nftBackOrder.setRefundCode(refundCode);
        nftBackOrder.setOrderId(orderId);
        nftBackOrder.setOrderCode(NftOrder.getOrderCode());
        nftBackOrder.setStoreId(NftOrder.getStoreId());
        nftBackOrder.setUserId(NftOrder.getUserId());
        nftBackOrder.setSkuIdNums(NftOrder.getSkuId());
        nftBackOrder.setRealBackPrice(refundPrice);
        nftBackOrder.setStatus(GoblinStatusConst.NftStatus.ORDER_REFUND_STATUS_1.getValue());
        nftBackOrder.setCreatedAt(now);
        nftBackOrder.setUpdatedAt(now);

        GoblinNftOrderCallBackVo backOrderVo = GoblinNftOrderCallBackVo.getNew().copy(nftBackOrder);

        //调用退款
        NftOrder.setPaymentId(paymentId);
        NftOrder.setPaymentType(paymentType);
        String returnString = initRefund(NftOrder, refundPrice, refundCode);
        HashMap hashMapResult = JsonUtils.fromJson(returnString, HashMap.class);
        Boolean success = (Boolean) hashMapResult.get("success");
        String message = (String) hashMapResult.get("message");
        if (!success) {
            if (!Objects.equals(backOrderVo.getStatus(), GoblinStatusConst.NftStatus.ORDER_REFUND_STATUS_2.getValue())) {
                backOrderVo.setStatus(GoblinStatusConst.NftStatus.ORDER_REFUND_STATUS_3.getValue());
                backOrderVo.setErrorReason(backOrderVo.getErrorReason() + ",失败原因：" + message);
                log.error("REFUND DATA = " + returnString);
            }
        }
        // redis
        setBackOrderVo(backOrderVo);
        // mongo
        goblinMongoUtils.insertGoblinNftOrderRefundVo(backOrderVo);
        // 添加退款
        queueUtils.sendMsgByRedis(
                MQConst.GoblinQueue.GOBLIN_STORE_ORDER_OPERA.getKey(),
                SqlMapping.get("goblin_nft_order_refund.insert",
                        nftBackOrder.getOrderRefundId(), nftBackOrder.getRefundCode(), nftBackOrder.getOrderId(),
                        nftBackOrder.getOrderCode(), nftBackOrder.getStoreId(), nftBackOrder.getUserId(),
                        nftBackOrder.getSkuIdNums(), nftBackOrder.getRealBackPrice(), nftBackOrder.getStatus(),
                        nftBackOrder.getRefundAt(), nftBackOrder.getErrorReason()
                )
        );
        if (success) {
            return true;
        } else {
            log.error("退款失败:" + message);
            return false;
        }
    }

    private String initRefund(GoblinNftOrderVo orderVo, BigDecimal price, String refundCode) {
        MultiValueMap<String, String> params = CollectionUtil.linkedMultiValueMapStringString();
        params.add("code", orderVo.getPayCode());
        params.add("notifyUrl", synUrl);
        params.add("orderCode", orderVo.getOrderCode());
        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(price));
        params.add("reason", "NFT超时支付");
        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;
    }

}
