package cn.freemud.management.service.impl;

import cn.freemud.base.entity.BaseResponse;
import cn.freemud.management.constant.ResponseCodeConstant;
import cn.freemud.management.entities.dto.request.console.*;
import cn.freemud.management.entities.dto.request.order.OrderManagerRequest;
import cn.freemud.management.entities.dto.response.order.OrderManagerResponse;
import cn.freemud.management.entities.dto.response.pay.PayRefundResponse;
import cn.freemud.management.enums.OperateType;
import cn.freemud.management.handler.AssisantApplicationHandler;
import cn.freemud.management.enums.*;
import cn.freemud.management.intercept.OrderServiceException;
import cn.freemud.management.service.OrderBaseService;
import cn.freemud.management.service.OrderManagerService;
import cn.freemud.management.service.handle.*;
import cn.freemud.management.thirdparty.ConsoleApiClient;
import cn.freemud.management.thirdparty.OrderCallbackClient;
import cn.freemud.management.util.ResponseUtil;
import com.alibaba.fastjson.JSONObject;
import com.freemud.application.sdk.api.log.ApiLog;
import com.freemud.application.sdk.api.log.LogThreadLocal;
import com.freemud.application.sdk.api.ordercenter.config.OrderCenterProperties;
import com.freemud.application.sdk.api.ordercenter.entities.v1.OrderBeanV1;
import com.freemud.application.sdk.api.ordercenter.entities.vo.OrderCallBackRequestVo;
import com.freemud.application.sdk.api.ordercenter.enums.*;
import com.freemud.application.sdk.api.ordercenter.enums.orderv1.OrderSourceV1;
import com.freemud.application.sdk.api.ordercenter.enums.orderv1.OrderStatusV1;
import com.freemud.application.sdk.api.ordercenter.request.OrderCancelReq;
import com.freemud.application.sdk.api.ordercenter.request.OrderExpressReq;
import com.freemud.application.sdk.api.ordercenter.request.OrderExtInfoDto;
import com.freemud.application.sdk.api.ordercenter.request.OrderExtendedReq;
import com.freemud.application.sdk.api.ordercenter.response.OrderBaseResp;
import com.freemud.application.sdk.api.ordercenter.service.OrderSdkService;
import com.freemud.application.sdk.api.service.EmailAlertService;
import com.freemud.application.sdk.api.storecenter.service.StoreCenterService;
import com.freemud.sdk.api.assortment.order.enums.PayRefundStatus;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.freemud.management.enums.OperateType.ORDER_AGREE_REFUND;

/**
 * All rights Reserved, Designed By www.freemud.cn
 *
 * @version V1.0
 * @Title: rrr
 * @Package cn.freemud.management.service.impl
 * @Description: saas订单履单操作
 * @author: shuhu.hou
 * @date: 2020/3/26 16:01
 * @Copyright: 2020 www.freemud.cn Inc. All rights reserved.
 * 注意：本内容仅限于上海非码科技内部传阅，禁止外泄以及用于其他的商业目
 */
@Service
public class SaasOrderMangerServiceImpl implements OrderManagerService {

    @Autowired
    private SaasOrderHandle saasOrderHandle;
    @Autowired
    private OrderBaseService orderBaseService;
    @Autowired
    private StoreCenterService storeCenterService;
    @Autowired
    private PaymentHandle paymentHandle;
    @Autowired
    private StockHandle stockHandle;
    @Autowired
    private DeliveryHandle deliveryHandle;
    @Autowired
    private OrderVerifyHandle orderVerifyHandle;
    @Autowired
    private OrderSdkService orderSdkService;
    @Autowired
    private EmailAlertService emailAlertService;
    @Autowired
    private AssisantApplicationHandler assisantApplicationHandler;
    private static final int SUCCESS = 100;

    /**
     * 先定义一个过滤集合，后续其他逻辑再分
     * 8200201  商户余额不足
     */
    public static final Set<String> PAY_RETURN_FILTER_CODES = Stream.of("8200201").collect(Collectors.toSet());
    @Autowired
    private OrderCenterProperties orderCenterProperties;
    @Autowired
    private OrderCallbackClient orderCallbackClient;

    @Autowired
    private ConsoleApiClient consoleApiClient;

    /**
     * 接单
     *
     * @param request   请求参数
     * @param orderBean 订单实体
     * @return
     */
    @Override
    public BaseResponse<OrderManagerResponse> orderConfirm(OrderManagerRequest request, OrderBeanV1 orderBean) {
        QueryFlag query = QueryFlag.builder().queryBusinessInfo(true).queryStoreInfo(true).build();
        ConsoleResponseDTO<BizDTO>  storeMix = this.getStoreMix(query, orderBean.getCompanyId(), orderBean.getShopId());
        boolean idAutoCreate = false;
        if (storeMix!=null && ObjectUtils.equals(ResponseResult.SUCCESS.getCode(), storeMix.getStatusCode())) {
            BizDTO bizVO = storeMix.getBizVO();
            // fisherman 预约单不走自动|半自动派单逻辑  【【野萃山】手动派单增加半自动配置】 https://www.tapd.cn/43862731/prong/stories/view/1143862731001040800
            boolean reservedExpress = Objects.equals(orderBean.getNewOrderType(), OrderType.GENERAL_EXPRESS.getIndex());
            // fisherman 自配送 不走 自动 | 半自动逻辑
            boolean deliveryTypeSelf = deliveryHandle.deliveryTypeSelf(Objects.isNull(orderBean.getAddInfo()) ? null : orderBean.getAddInfo().getDeliveryType());
            if (bizVO != null && bizVO.getBusinessInfo() != null && reservedExpress && !deliveryTypeSelf) {
                ExpandFieldsDTO expandFields = bizVO.getBusinessInfo().getExpandFields();
                request.setDispatchType(expandFields.getDispatchType());
                // fisherman 半自动派单时间获取
                request.setDispatchTimeout(deliveryHandle.getDispatchTimeout(expandFields.getDispatchConfig()));
                idAutoCreate = true;
            }
            // fisherman 到店,自提 出餐时间->订单接单状态流转 timeout字段维护  【【POS】业务设置】 https://www.tapd.cn/43862731/prong/stories/view/1143862731001044130
            if (Objects.nonNull(bizVO) && Objects.nonNull(bizVO.getBusinessInfo())) {
                // 必须是 到店订单
                boolean eatIn = Objects.equals(orderBean.getNewOrderType(), OrderType.GENERAL_DINE_IN.getIndex());
                if (eatIn) {
                    BusinessInfoDTO businessInfo = bizVO.getBusinessInfo();
                    request.setTimeout(deliveryHandle.getPeakTimeDelivery(businessInfo));
                }
            }
        }
        // 订单接单
        BaseResponse baseResponse = saasOrderHandle.orderConfirm(request, orderBean);
        // 使用feign调用 获取门店信息
        // 创建配送单
        deliveryHandle.createDelivery(orderBean, request, storeMix, idAutoCreate);
        // 推送pos、微信消息中心 重复接单不重复推消息（针对蜜雪做的修改）
        if(baseResponse != null && baseResponse.getResult() == null){
            orderBaseService.sendMessage(orderBean, OperateType.ORDER_CONFIRM, request.getReason());
        }
        // 增加全局开关，当紧急方案打开时进行直接处理callBack消息
        if (orderCenterProperties.isUrgentCallbackOpen()) {
            OrderCallBackRequestVo requestVo = saasOrderHandle.convert2CallbackReq(orderBean.getOid(),3,null,null);
            ApiLog.infoMessage("紧急方案 接单成功直接调用callback,orderCode:{},requestId:{}",requestVo.getOrderCode(),requestVo.getRequestId());
            orderCallbackClient.callbackOrder(requestVo);
        }
        return ResponseUtil.success(new OrderManagerResponse(storeMix.getBizVO().getBusinessInfo().getOrderPrintConfig(), orderBean.getGmtExpect(),
                CollectionUtils.isEmpty(orderBean.getRefundList()) ? null : RefundStatus.getByCode(orderBean.getRefundList().get(0).getStatus())));
    }

    /**
     * 制作完成
     *
     * @param request
     * @param orderBean
     * @return
     */
    @Override
    public BaseResponse<OrderManagerResponse> orderDone(OrderManagerRequest request, OrderBeanV1 orderBean) {
        // 订单制作完成
        saasOrderHandle.orderDone(request, orderBean);
        // 推送pos、微信消息中心
        orderBaseService.sendMessage(orderBean, OperateType.ORDER_DONE, request.getReason());
        return ResponseUtil.success();
    }

    /**
     * 订单配送
     *
     * @param request
     * @param orderBean
     * @return
     */
    @Override
    public BaseResponse<OrderManagerResponse> orderDelivery(OrderManagerRequest request, OrderBeanV1 orderBean) {
        // 订单配送
        saasOrderHandle.orderDelivery(request, orderBean);
        // 推送pos、微信消息中心
        orderBaseService.sendMessage(orderBean, OperateType.ORDER_SEND, request.getReason());
        return ResponseUtil.success();
    }

    /**
     * 订单完成
     *
     * @param request
     * @param orderBean
     * @return
     */
    @Override
    public BaseResponse<OrderManagerResponse> orderAffirm(OrderManagerRequest request, OrderBeanV1 orderBean) {
        // 订单完成
        saasOrderHandle.orderAffirm(request, orderBean);
        // 推送pos、微信消息中心
        orderBaseService.sendMessage(orderBean, OperateType.ORDER_AFFIRM, request.getReason());
        return ResponseUtil.success();
    }

    /**
     * 拒单
     *
     * @param request
     * @param orderBean
     * @return
     */
    @Override
    public BaseResponse<OrderManagerResponse> orderReject(OrderManagerRequest request, OrderBeanV1 orderBean) {
        //支付退款
        PayRefundResponse refundResponse ;
        try {
            if(null != orderBean.getOrderPayItem() && orderBean.getOrderPayItem().size()>0){
                refundResponse = paymentHandle.multiRefund(orderBean);
            }else{
                refundResponse = paymentHandle.refund(request, orderBean);
            }
        } catch (OrderServiceException orderEx){ // 爱马哥兼容，不抛错
            return ResponseUtil.error(orderEx.getResult());
        }
        //订单拒单
        saasOrderHandle.orderReject(request, refundResponse, orderBean);
        // 推送pos、微信消息中心
        orderBaseService.sendMessage(orderBean, OperateType.ORDER_REJECT, request.getReason());
        //todo  可以考虑基于订单回调异步实现
        //冲正库存
        stockHandle.revert(request,orderBean);
        return ResponseUtil.success();
    }



    /**
     * 同意退款
     *
     * @param request
     * @param orderBean
     * @return
     */
    @Override
    public BaseResponse<OrderManagerResponse> orderAgreeRefund(OrderManagerRequest request, OrderBeanV1 orderBean) {
        //取消配送单
        deliveryHandle.cancelDelivery(orderBean,request);
        //支付退款
        PayRefundResponse refundResponse;
        try {
            if(null != orderBean.getOrderPayItem() && orderBean.getOrderPayItem().size()>0){
                refundResponse = paymentHandle.multiRefund(orderBean);
            }else{
                OrderExtendedReq ext = orderBean.getOrderExtended();
                if (StringUtils.isNotBlank(ext.getAgentPayerId()) && !Objects.equals(ext.getAgentPayerId(), orderBean.getUserId())) {
                    //代付人信息不为空  并且和订单创建人不一样，表示代付单
                    refundResponse = paymentHandle.agentPayRefund(orderBean);
                } else {
                    //正常订单现金退款
                    refundResponse = paymentHandle.refund(request, orderBean);
                }
            }
        } catch (OrderServiceException orderEx){ // 爱马哥兼容，不抛错
            return ResponseUtil.error(orderEx.getResult());
        }
        //订单同意退款
        saasOrderHandle.refundAgree(request, refundResponse, orderBean);
        // 推送pos、微信消息中心
        orderBaseService.sendMessage(orderBean, ORDER_AGREE_REFUND, request.getReason());
        //todo  可以考虑基于订单回调异步实现
        //冲正库存
        stockHandle.revert(request,orderBean);
        return ResponseUtil.success();
    }

    /**
     * 拒绝退款
     *
     * @param request
     * @param orderBean
     * @return
     */
    @Override
    public BaseResponse<OrderManagerResponse> orderRejectRefund(OrderManagerRequest request, OrderBeanV1 orderBean) {
        //拒绝退款
        saasOrderHandle.refundReject(request,orderBean);
        // 推送pos、微信消息中心
        orderBaseService.sendMessage(orderBean, OperateType.ORDER_REJECT_REFUND, request.getReason());
        return ResponseUtil.success();
    }

    /**
     * 取消订单
     */
    @Override
    public BaseResponse<OrderManagerResponse> orderCancel(OrderManagerRequest request, OrderBeanV1 orderBean){
        if (BizTypeEnum.ORDINARY.getBizType().compareTo(orderBean.getBizType()) == 0
                &&  MarketTypeEnum.TIKTOK_MARKET_ORDER.getIndex().compareTo(Byte.toUnsignedInt(orderBean.getMarketingType())) == 0) {
            this.orderAgreeRefund(request, orderBean);
            return ResponseUtil.success();
        }
        List<Integer> newOrderStatusList = Arrays.asList(OrderStatusV1.RECEIPT.getV2Code(),OrderStatusV1.COMPLETE.getV2Code(),OrderStatusV1.COMPLETE_MAKE.getV2Code());
        List<String> sourceList = Arrays.asList(OrderSourceV1.SAAS.getCode(),OrderSourceV1.ALIPAY.getCode(),OrderSourceV1.APP.getCode());
        if (sourceList.contains(orderBean.getSource()) && newOrderStatusList.contains(orderBean.getStatusV2())) {
           return executeRefund(request,orderBean, OperateType.ORDER_REJECT.getOpType());
        } else if (OrderSourceV1.MEAL.getCode().equals(orderBean.getSource())) {
            if (OrderStatusV1.WAIT_PAY.getV2Code().equals(orderBean.getStatusV2()) || PayType.CASH_ON_DELIVERY.getCode().compareTo(orderBean.getPayType()) == 0) {
                return executeCancel(request,orderBean, PayRefundStatus.SUCCESS.getCode(), AfterSalesType.SYSTEM_CANCEL.getIndex(), Integer.valueOf(orderBean.getOrderClient()));
            } else {
                return executeRefund(request,orderBean, OperateType.ORDER_REJECT.getOpType());
            }
        } else if (OrderSourceV1.POS.getCode().equals(orderBean.getSource())) {
            return posCancel(orderBean);
        }
        return ResponseUtil.success();
    }

    /**
     * 退款操作
     * @param request
     * @param orderBean
     * @param operationType
     * @return
     */
    private BaseResponse<OrderManagerResponse> executeRefund(OrderManagerRequest request,OrderBeanV1 orderBean, String operationType) {
        //订单接单参数校验
        BaseResponse verifyResponse = orderVerifyHandle.orderCancel(orderBean, OperateType.ORDER_AGREE_REFUND.getOpType());
        if (ObjectUtils.notEqual(verifyResponse.getCode(), ResponseResult.SUCCESS.getCode())) {
            return ResponseUtil.error(verifyResponse.getCode());
        }
        BaseResponse<OrderManagerResponse> baseResponse = null;
        //调用oms拒绝订单
        if (operationType.equalsIgnoreCase(OperateType.ORDER_REJECT.getOpType())) {
            baseResponse = this.orderReject(request, orderBean);
        }
        if(null == baseResponse || !ObjectUtils.equals(SUCCESS,Integer.valueOf(baseResponse.getCode()))){
            if (PAY_RETURN_FILTER_CODES.contains(baseResponse.getCode())) {
                return ResponseUtil.error(ResponseResult.getResponseResult(baseResponse.getCode()));
            }
            emailAlertService.sendEmailAlert("商家取消订单失败", "请求json:" + JSONObject.toJSONString(orderBean) + "返回msg:" + baseResponse.getMessage());
            return ResponseUtil.error(ResponseResult.PARTNER_ORDER_CANCEL_ERROR);
        }
        return ResponseUtil.success();
    }

    /**
     * 拒单在支付退款后的取消订单操作
     *
     * @param order          订单详情
     * @param refundStatus   支付退款状态
     * @return
     */
    private BaseResponse<OrderManagerResponse> executeCancel(OrderManagerRequest request,OrderBeanV1 order, Integer refundStatus, Integer afterSalesType, Integer orderClient) {
        Integer createEvent;
        if (PayRefundStatus.RUNNING.getCode().equals(refundStatus)) {
            createEvent = CreateEventEnum.FIVE.getType();
        } else if (PayRefundStatus.SUCCESS.getCode().equals(refundStatus)) {
            createEvent = CreateEventEnum.FOUR.getType();
        } else {
            createEvent = CreateEventEnum.FIVE.getType();
        }
        OrderCancelReq orderCancelReq = new OrderCancelReq();
        orderCancelReq.setPartnerId(order.getCompanyId());
        orderCancelReq.setOrderCode(order.getOid());
        orderCancelReq.setCancelReason(request.getReason());
        orderCancelReq.setAfterSalesType(afterSalesType);
        orderCancelReq.setCreateEvent(createEvent);
        orderCancelReq.setOrderClient(orderClient == null ? OrderClientType.SAAS.getIndex() : orderClient);
        orderCancelReq.setOperator(request.getOperator());
        OrderBaseResp baseResponse = orderSdkService.cancelOrder(orderCancelReq,UUID.randomUUID().toString());
        if (!ObjectUtils.equals(SUCCESS,Integer.valueOf(baseResponse.getCode()))) {
            this.commonSendEmailAlert(order,baseResponse,"拒单在支付退款后的取消订单操作失败");
            return ResponseUtil.error(ResponseResult.PARTNER_ORDER_CANCEL_ERROR);
        }
        return ResponseUtil.success();
    }

    public BaseResponse<OrderManagerResponse> posCancel(OrderBeanV1 order) {
        //调用cancel接口，商家退款
        OrderCancelReq orderCancelReq = new OrderCancelReq();
        orderCancelReq.setPartnerId(order.getCompanyId());
        orderCancelReq.setOrderCode(order.getOid());
        orderCancelReq.setCancelReason("商家取消");
        orderCancelReq.setAfterSalesType(AfterSalesType.PARTNER_CANCEL.getIndex());
        orderCancelReq.setCreateEvent(CreateEventEnum.FOUR.getType());
        orderCancelReq.setOrderClient(OrderClientType.POS.getIndex());
        OrderBaseResp baseResponse = orderSdkService.cancelOrder(orderCancelReq,UUID.randomUUID().toString());
        if (!Objects.equals(SUCCESS,Integer.valueOf(baseResponse.getCode()))){
            this.commonSendEmailAlert(order,baseResponse,"posCancel 取消订单失败");
            return ResponseUtil.error(ResponseResult.PARTNER_ORDER_CANCEL_ERROR);
        }
        // 储值卡退款
        OrderExtInfoDto orderExtInfoDto = JSONObject.parseObject(order.getExtInfo(), OrderExtInfoDto.class) == null ? new OrderExtInfoDto() : JSONObject.parseObject(order.getExtInfo(), OrderExtInfoDto.class);
        //支付退款
        if (orderExtInfoDto != null  && orderExtInfoDto.getSvcAmount()!= null && StringUtils.isNotEmpty(orderExtInfoDto.getSvcCardCode())  && order.getPayStatus() > 1){
            PayRefundResponse refundResponse = paymentHandle.posOrderPayRefund(order, orderExtInfoDto);
            if(!ObjectUtils.equals(PayRefundStatus.SUCCESS,refundResponse.getPayRefundStatus())){
                return ResponseUtil.error(ResponseResult.PARTNER_ORDER_CANCEL_ERROR);
            }
        }
        return ResponseUtil.success();
    }

    private void commonSendEmailAlert(OrderBeanV1 order, OrderBaseResp baseResponse,String desc){
        emailAlertService.sendEmailAlert(desc, "请求json:" + JSONObject.toJSONString(order) + "返回msg:" + baseResponse.getMessage());
    }

    @Override
    public BaseResponse<OrderManagerResponse> orderCreateDelivery(OrderManagerRequest request, OrderBeanV1 orderBean) {
        // 使用feign调用 获取门店信息
        QueryFlag query = QueryFlag.builder().queryBusinessInfo(true).queryStoreInfo(true).build();
        ConsoleResponseDTO<BizDTO>  storeMix = this.getStoreMix(query, orderBean.getCompanyId(), orderBean.getShopId());
        // 创建配送单
        return deliveryHandle.createDelivery(orderBean, request, storeMix, false);
    }

    @Override
    public BaseResponse orderCancelDelivery(OrderManagerRequest request, OrderBeanV1 orderBean) {
        BaseResponse response =  deliveryHandle.cancelDelivery(orderBean,request);
        if (!Objects.equals(response.getCode(), ResponseCodeConstant.RESPONSE_SUCCESS_STR)){
            return response;
        }
        OrderExpressReq expressReq = new OrderExpressReq();
        expressReq.setOrderCode(orderBean.getOid());
        expressReq.setPartnerId(orderBean.getCompanyId());
        expressReq.setOrderSubState(DeliveryStatus.DELIVERYCANCEL.getCode());
        OrderBaseResp orderBaseResp =  orderSdkService.updateDeliveryInfo(expressReq, LogThreadLocal.getTrackingNo());
        if (!Objects.equals(orderBaseResp.getCode(), ResponseCodeConstant.RESPONSE_SUCCESS_STR)){
            this.commonSendEmailAlert(orderBean,orderBaseResp,"取消配送,修改订单配送状态失败");
            return ResponseUtil.error(ResponseResult.ORDER_DELIVERY_EDIT_FAILED);
        }
        return ResponseUtil.success();
    }

    /**
     *
     * @param query
     * @param partnerId
     * @param storeId
     * @return
     */
    private ConsoleResponseDTO<BizDTO>  getStoreMix(QueryFlag query, String partnerId, String storeId) {
        GetStoreMixRequest getStoreMixRequest = GetStoreMixRequest.builder().partnerId(partnerId).storeCode(storeId).build();
        getStoreMixRequest.setQuery(query);
        ConsoleResponseDTO<BizDTO> storeMix = consoleApiClient.getStoreMix(getStoreMixRequest);
        return storeMix;
    }
}
