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

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.IGoblinStoreBackOrderService;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.MultiValueMap;

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

@Service
@Slf4j
public class GoblinStoreBackOrderServiceImpl implements IGoblinStoreBackOrderService {
    // todo hujiachen 日志没加
    @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<GoblinStoreBackOrderListVo>> orderBackList(Integer page, String orderBackCode, Integer type, String cst, String cet, String orderCode, String spuName, Integer status) {
        List<GoblinStoreBackOrderListVo> listVos = ObjectUtil.goblinStoreBackOrderListVoArrayList();
        String uid = CurrentUtil.getCurrentUid();
        GoblinStoreInfoVo storeInfoVo = redisUtils.getStoreInfoVoByUid(uid);
        if (storeInfoVo == null) {
            return ResponseDto.failure("无法查看");
        }
        HashMap<String, Object> map = mongoUtils.storeBackOrderList(storeInfoVo.getStoreId(), page, orderBackCode, type, cst, cet, orderCode, spuName, status);
        long total = (long) map.get("total");
        List<GoblinBackOrderVo> voList = (List<GoblinBackOrderVo>) map.get("data");
        for (GoblinBackOrderVo item : voList) {
            GoblinStoreBackOrderListVo vo = GoblinStoreBackOrderListVo.getNew();
            vo.setCreatedAt(item.getCreatedAt());
            vo.setBackOrderId(item.getBackOrderId());
            vo.setBackCode(item.getBackCode());
            vo.setBackOrderSkuVos(item.getBackOrderSkuVos());
            vo.setOrderCode(item.getOrderCode());
            vo.setRealBackPrice(item.getBackOrderId());
            vo.setStatus(item.getBackOrderId());
            vo.setType(item.getBackOrderId());
            listVos.add(vo);
        }
        PageInfo<GoblinStoreBackOrderListVo> pageInfo = new PageInfo(listVos);
        pageInfo.setTotal(total);
        return ResponseDto.success(pageInfo);
    }

    @Override
    public ResponseDto<GoblinBackOrderDetailsVo> orderDetails(String backOrderId) {
        String uid = CurrentUtil.getCurrentUid();
        GoblinStoreInfoVo storeInfoVo = redisUtils.getStoreInfoVoByUid(uid);
        if (storeInfoVo == null) {
            return ResponseDto.failure("无法查看");
        }
        GoblinBackOrderVo backOrderVo = redisUtils.getBackOrderVo(backOrderId);
        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(backOrderVo.getOrderId());
        GoblinBackOrderDetailsVo vo = GoblinBackOrderDetailsVo.getNew();
        BeanUtils.copyProperties(backOrderVo, vo);
        vo.setPayTime(orderVo.getPayTime());
        vo.setPriceVoucher(orderVo.getPriceVoucher());
        vo.setPriceExpress(orderVo.getPriceExpress());
        vo.setPriceActual(orderVo.getPriceActual());
        vo.setIsMember(orderVo.getIsMember());
        vo.setUserName(orderVo.getUserName());
        vo.setUserMobile(orderVo.getUserMobile());
        List<GoblinOrderSkuVo> orderSkuVoList = ObjectUtil.getGoblinOrderSkuVoArrayList();
        for (String orderSkuVoId : orderVo.getOrderSkuVoIds()) {
            GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuVoId);
            orderSkuVoList.add(orderSkuVo);
        }
        vo.setOrderSkuVoList(orderSkuVoList);
        return ResponseDto.success(vo);
    }

    @Override
    public ResponseDto<Boolean> changeExpressRefund(String backOrderId, BigDecimal refundPrice) {
        String uid = CurrentUtil.getCurrentUid();
        LocalDateTime now = LocalDateTime.now();
        GoblinStoreInfoVo storeInfoVo = redisUtils.getStoreInfoVoByUid(uid);
        if (storeInfoVo == null) {
            return ResponseDto.failure("无法查看");
        }
        GoblinBackOrderVo backOrderVo = redisUtils.getBackOrderVo(backOrderId);
        BigDecimal sub = backOrderVo.getBackPriceExpress().subtract(refundPrice);
        backOrderVo.setBackPriceExpress(refundPrice);
        backOrderVo.setRealBackPrice(backOrderVo.getRealBackPrice().subtract(sub));
        //添加日志
        GoblinBackOrderLog backOrderLog = initBackLog(backOrderId, uid, now);
        backOrderLog.setStatus(GoblinStatusConst.Status.ORDER_LOG_STATUS_22.getValue());
        backOrderLog.setOperationType(GoblinStatusConst.Type.OPERATION_TYPE_2.getValue());
        backOrderLog.setMessage("商户退款-修改快递费：backOrderId=[" + backOrderId + "],refundPrice=[" + refundPrice + "]");

        //redis
        redisUtils.setBackOrderVo(backOrderId, backOrderVo);
        //mongo
        mongoUtils.updateGoblinBackOrderVo(backOrderId, backOrderVo);
        //mysql
        queueUtils.sendMsgByRedis(
                MQConst.GoblinQueue.GOBLIN_STORE_ORDER_OPERA.getKey(),
                SqlMapping.get("goblin_order.store.changeExpress",
                        backOrderVo.getRealBackPrice(), backOrderVo.getBackPriceExpress(), now,
                        backOrderId, now, now
                )
        );
        //添加日志
        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
                )
        );
        return ResponseDto.success();
    }

    @Override
    public ResponseDto<Boolean> agreeRefund(String backOrderId) {
        String uid = CurrentUtil.getCurrentUid();
        LocalDateTime now = LocalDateTime.now();
        GoblinStoreInfoVo storeInfoVo = redisUtils.getStoreInfoVoByUid(uid);
        if (storeInfoVo == null) {
            return ResponseDto.failure("无法查看");
        }
        GoblinBackOrderVo backOrderVo = redisUtils.getBackOrderVo(backOrderId);
        backOrderVo.setStatus(GoblinStatusConst.Status.ORDER_BACK_STATUS_0.getValue());
        //添加日志
        GoblinBackOrderLog backOrderLog = initBackLog(backOrderId, uid, now);
        backOrderLog.setStatus(GoblinStatusConst.Status.ORDER_LOG_STATUS_22.getValue());
        backOrderLog.setOperationType(GoblinStatusConst.Type.OPERATION_TYPE_2.getValue());
        backOrderLog.setMessage("商户退款-同意退款：backOrderId=[" + backOrderId + "]");
        //调用退款
        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(backOrderId);
        String returnString = initRefund(orderVo, backOrderVo.getRealBackPrice(), backOrderVo.getBackCode());
        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(backOrderId, backOrderVo);
        //mongo
        mongoUtils.updateGoblinBackOrderVo(backOrderId, backOrderVo);
        //mysql
        queueUtils.sendMsgByRedis(
                MQConst.GoblinQueue.GOBLIN_STORE_ORDER_OPERA.getKey(),
                SqlMapping.get("goblin_order.store.applyRefund",
                        backOrderVo.getStatus(),backOrderVo.getReason(), now,
                        backOrderId, now, now
                )
        );
        //添加日志
        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
                )
        );
        return ResponseDto.success();
    }

    @Override
    public ResponseDto<Boolean> refusedRefund(String backOrderId) {
        String uid = CurrentUtil.getCurrentUid();
        LocalDateTime now = LocalDateTime.now();
        GoblinStoreInfoVo storeInfoVo = redisUtils.getStoreInfoVoByUid(uid);
        if (storeInfoVo == null) {
            return ResponseDto.failure("无法查看");
        }
        GoblinBackOrderVo backOrderVo = redisUtils.getBackOrderVo(backOrderId);
        backOrderVo.setStatus(GoblinStatusConst.Status.ORDER_BACK_STATUS_3.getValue());
        //添加日志
        GoblinBackOrderLog backOrderLog = initBackLog(backOrderId, uid, now);
        backOrderLog.setStatus(GoblinStatusConst.Status.ORDER_LOG_STATUS_22.getValue());
        backOrderLog.setOperationType(GoblinStatusConst.Type.OPERATION_TYPE_2.getValue());
        backOrderLog.setMessage("商户退款-拒绝退款：backOrderId=[" + backOrderId + "]");
        //redis
        redisUtils.setBackOrderVo(backOrderId, backOrderVo);
        //mongo
        mongoUtils.updateGoblinBackOrderVo(backOrderId, backOrderVo);
        //mysql
        queueUtils.sendMsgByRedis(
                MQConst.GoblinQueue.GOBLIN_STORE_ORDER_OPERA.getKey(),
                SqlMapping.get("goblin_order.store.changeStatus",
                        backOrderVo.getStatus(), now,
                        backOrderId, now, now
                )
        );
        //添加日志
        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
                )
        );
        return ResponseDto.success();
    }

    @Override
    public ResponseDto<Boolean> changeSkuRefund(String backOrderId, BigDecimal refundPrice, String orderSkuId) {
        String uid = CurrentUtil.getCurrentUid();
        LocalDateTime now = LocalDateTime.now();
        GoblinStoreInfoVo storeInfoVo = redisUtils.getStoreInfoVoByUid(uid);
        if (storeInfoVo == null) {
            return ResponseDto.failure("无法查看");
        }
        BigDecimal sub = BigDecimal.ZERO;
        GoblinBackOrderVo backOrderVo = redisUtils.getBackOrderVo(backOrderId);
        for (GoblinBackOrderSkuVo backOrderSkuVo : backOrderVo.getBackOrderSkuVos()) {
            if (backOrderSkuVo.getOrderSkuId().equals(orderSkuId)) {
                sub = backOrderSkuVo.getRefundPrice().subtract(refundPrice);
                backOrderSkuVo.setRefundPrice(refundPrice);
                break;
            }
        }
        backOrderVo.setRealBackPrice(backOrderVo.getRealBackPrice().subtract(sub));
        //添加日志
        GoblinBackOrderLog backOrderLog = initBackLog(backOrderId, uid, now);
        backOrderLog.setStatus(GoblinStatusConst.Status.ORDER_LOG_STATUS_22.getValue());
        backOrderLog.setOperationType(GoblinStatusConst.Type.OPERATION_TYPE_2.getValue());
        backOrderLog.setMessage("商户退款-修改sku价格：backOrderId=[" + backOrderId + "],refundPrice=["+refundPrice+"],orderSkuId=["+orderSkuId+"]");
        //redis
        redisUtils.setBackOrderVo(backOrderId, backOrderVo);
        //mongo
        mongoUtils.updateGoblinBackOrderVo(backOrderId, backOrderVo);
        //mysql
        queueUtils.sendMsgByRedis(
                MQConst.GoblinQueue.GOBLIN_STORE_ORDER_OPERA.getKey(),
                SqlMapping.get("goblin_order.store.changeSku",
                        backOrderVo.getRealBackPrice(), now,
                        backOrderId, now, now
                )
        );
        //添加日志
        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
                )
        );
        return ResponseDto.success();
    }

    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;
    }
}
