package cn.freemud.management.service.handle;

import cn.freemud.base.entity.BaseResponse;
import cn.freemud.base.util.DateUtil;
import cn.freemud.management.adapter.DeliverySdkAdapter;
import cn.freemud.management.entities.dto.request.console.*;
import cn.freemud.management.entities.dto.request.delivery.DeliveryOrderHaltedRequest;
import cn.freemud.management.entities.dto.request.order.OrderManagerRequest;
import cn.freemud.management.enums.DeliveryStatus;
import cn.freemud.management.enums.ResponseResult;
import cn.freemud.management.service.OrderBaseService;
import cn.freemud.management.thirdparty.DeliveryMCCafeClient;
import cn.freemud.management.util.ResponseUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.freemud.application.sdk.api.deliverycenter.dto.CancelDeliveryOrderRequestDto;
import com.freemud.application.sdk.api.deliverycenter.dto.CreateDeliveryOrderRequestDto;
import com.freemud.application.sdk.api.deliverycenter.response.CreateDeliveryOrderResponseDto;
import com.freemud.application.sdk.api.deliverycenter.response.DeliveryResponseDto;
import com.freemud.application.sdk.api.deliverycenter.service.DeliveryService;
import com.freemud.application.sdk.api.log.ApiLog;
import com.freemud.application.sdk.api.log.LogThreadLocal;
import com.freemud.application.sdk.api.ordercenter.entities.v1.OrderBeanV1;
import com.freemud.application.sdk.api.ordercenter.enums.NewOrderStatus;
import com.freemud.application.sdk.api.ordercenter.util.LogUtil;
import com.freemud.application.sdk.api.service.EmailAlertService;
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.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * All rights Reserved, Designed By www.freemud.cn
 *
 * @version V1.0
 * @Title: 配送服务处理类
 * @Package cn.freemud.management.service.handle
 * @Description:
 * @author: shuhu.hou
 * @date: 2020/4/26 15:44
 * @Copyright: 2020 www.freemud.cn Inc. All rights reserved.
 * 注意：本内容仅限于上海非码科技内部传阅，禁止外泄以及用于其他的商业目
 */
@Component
public class DeliveryHandle {

    private static final String THIRD = "third";
    private static final String delivery_type_self = "self";
    private static final int SUCCESS = 100;

    @Value("${saas.order.delivery.callBackUrl}")
    private String deliveryCallBackUrl;
    @Value("${delivery.support.ordersource}")
    private String supportOrderSource;

    @Autowired
    private DeliveryService deliveryService;
    @Autowired
    private DeliverySdkAdapter deliverySdkAdapter;
    @Autowired
    private OrderBaseService orderBaseService;
    @Autowired
    private DeliveryMCCafeClient deliveryMCCafeClient;
    @Autowired
    private EmailAlertService emailAlertService;
    @Autowired
    private LogUtil logUtil;

    /**
     * 创建配送单
     * 【ID1036616】 【野萃山】【万象&小助手】支持门店手动创建运单，通知骑手到店取餐
     *
     * @param orderBean
     * @param request
     * @return
     */
    public BaseResponse createDelivery(OrderBeanV1 orderBean, OrderManagerRequest request, ConsoleResponseDTO<BizDTO> storeInfo, boolean idAutoCreate) {
        if (storeInfo == null || ObjectUtils.notEqual(ResponseResult.SUCCESS.getCode(), storeInfo.getStatusCode()) || storeInfo.getBizVO() == null || storeInfo.getBizVO().getStoreInfo() == null) {
            return ResponseUtil.error(ResponseResult.STORE_INFO_NOT_FOUND);
        }
        // 【ID1036616】 【野萃山】【万象&小助手】支持门店手动创建运单，通知骑手到店取餐
        BusinessInfoDTO businessInfo = storeInfo.getBizVO().getBusinessInfo();
        if (idAutoCreate && Objects.nonNull(businessInfo) && Objects.nonNull(businessInfo.getExpandFields())) {
            ExpandFieldsDTO expandFields = businessInfo.getExpandFields();
            String dispatchType = expandFields.getDispatchType();
            // 1. 手动派单
            if (Objects.equals(dispatchType, "1")) {
                ApiLog.printLog("oms 门店自动创建运单->", JSON.toJSONString(orderBean.getOid()), null, null);
                return ResponseUtil.success();
            }
        }
        if (!checkOrderOfDelivery(orderBean)) {
            return ResponseUtil.success();
        }
        // 调用配送系统创建配送单
        CreateDeliveryOrderRequestDto requestDto = deliverySdkAdapter.buildDeliveryOrderRequestDto(orderBean, storeInfo, deliveryCallBackUrl);
        CreateDeliveryOrderResponseDto deliveryResponse = deliveryService.deliveryOrderAdd(requestDto, LogThreadLocal.getTrackingNo());

        String operator = request == null || StringUtils.isBlank(request.getOperator()) ? "系统" : request.getOperator();
        //创建配送单失败，更新订单为异常单
        if (deliveryResponse == null || SUCCESS != deliveryResponse.getCode() || deliveryResponse.getData() == null) {
            String deliveryId = deliveryResponse != null && deliveryResponse.getData() != null ? deliveryResponse.getData().getDeliveryId() : "";
            orderBaseService.updateDeliveryAbnormal(orderBean.getCompanyId(), orderBean.getOid(), deliveryId, operator, deliveryResponse == null ? "" : deliveryResponse.getMsg());
            return ResponseUtil.error(deliveryResponse == null ? "调用配送服务失败" : deliveryResponse.getMsg());
        }
        // 创建配送单成功
        orderBaseService.updateDeliverySuccess(orderBean.getOid(), deliveryResponse.getData().getDeliveryId(), operator, orderBean.getCompanyId());
        return ResponseUtil.success();
    }

    /**
     * 取消配送
     *
     * @param data
     * @param request
     * @return
     */
    public BaseResponse cancelDelivery(OrderBeanV1 data, OrderManagerRequest request) {
        if(Objects.equals(NewOrderStatus.PLACE_AN_ORDER.getIndex(),data.getStatusV2())){
            return ResponseUtil.success();
        }
        if (data.getOrderType() == 1 && data.getAddInfo() != null && ObjectUtils.equals(data.getAddInfo().getDeliveryType(), THIRD)) {
            Integer deliverStatus = data.getAddInfo().getDeliverStatus();
            //运单异常或取消时，无需作废三方配送运单
            if (ObjectUtils.equals(DeliveryStatus.DELIVERYERROR.getCode(), deliverStatus)
                    || ObjectUtils.equals(DeliveryStatus.DELIVERYCANCEL.getCode(), deliverStatus)
                    || ObjectUtils.equals(DeliveryStatus.DELIVERYARRIVED.getCode(), deliverStatus)) {
                return ResponseUtil.success();
            }
            //运单状态非待接单或系统接单时，不能取消运单
            if (ObjectUtils.equals(DeliveryStatus.RIDERSTARTDELIVERY.getCode(), deliverStatus)) {
                return ResponseUtil.error(ResponseResult.DELIVERY_CANCEL_ORDER_ERROR);
            }
            CancelDeliveryOrderRequestDto cancelDeliveryOrderRequestDto = new CancelDeliveryOrderRequestDto();
            cancelDeliveryOrderRequestDto.setDeliveryId(data.getAddInfo().getDeliveryId());
            cancelDeliveryOrderRequestDto.setOrderCancelCode(4);
            //商家退款取消配送
            cancelDeliveryOrderRequestDto.setOrderCancelDescription("顾客取消订单");
            DeliveryResponseDto deliveryResponse = deliveryService.deliveryOrderCancel(cancelDeliveryOrderRequestDto, LogThreadLocal.getTrackingNo());
            if (deliveryResponse == null || !StringUtils.equals(ResponseResult.SUCCESS.getCode(), deliveryResponse.getCode() + "")) {
                return ResponseUtil.error(ResponseResult.DELIVERY_CANCEL_ORDER_ERROR);
            }
        }
        return ResponseUtil.success();
    }

    /**
     * 配送停单
     *
     * @param data
     * @return
     */
    public BaseResponse haltedDelivery(OrderBeanV1 data) {
        if (data.getOrderType() == 1 && data.getAddInfo() != null && ObjectUtils.equals(data.getAddInfo().getDeliveryType(), THIRD)) {
            DeliveryOrderHaltedRequest deliveryOrderHaltedRequest = new DeliveryOrderHaltedRequest();
            deliveryOrderHaltedRequest.setHaltedReason("foe入机失败");
            deliveryOrderHaltedRequest.setOrderKey(data.getOid());
            deliveryOrderHaltedRequest.setStoreId(data.getShopId());
            DeliveryResponseDto deliveryResponse = deliveryMCCafeClient.halted(deliveryOrderHaltedRequest);
            if (deliveryResponse == null || !StringUtils.equals(ResponseResult.SUCCESS.getCode(), deliveryResponse.getCode() + "")) {
                emailAlertService.sendEmailAlert("配送单停单失败", String.format("request:%s \r\nresponse:%s", JSONObject.toJSONString(deliveryOrderHaltedRequest), JSONObject.toJSONString(deliveryResponse)));
                return ResponseUtil.error(ResponseResult.DELIVERY_ORDER_STOP_ERROR);
            }
        }
        return ResponseUtil.success();
    }


    /**
     * 校验是否要创建配送单
     *
     * @param orderBean
     * @return
     */
    private boolean checkOrderOfDelivery(OrderBeanV1 orderBean) {
        //判断外卖单
        if (1 != orderBean.getOrderType()) {
            return false;
        }
        //订单来源异常
        boolean sourceCheck = false;
        String[] supportSource = supportOrderSource.split(","); // OrderSourceType.SAAS.getCode()
        for (String source : supportSource) {
            if (orderBean.getSource().equalsIgnoreCase(source)) {
                sourceCheck = true;
                break;
            }
        }
        if (!sourceCheck) {
            return false;
        }
        //配送信息为空，则不创建配送单
        if (orderBean.getAddInfo() == null || orderBean.getAddInfo().getDeliveryType() == null) {
            return false;
        }
        //自配送不创建配送单
        if (this.deliveryTypeSelf(orderBean.getAddInfo().getDeliveryType())) {
            return false;
        }
        return true;
    }

    /**
     * 半自动派单 获取时间区间范围
     * 对外暴露的方法
     *
     * @param dispatchConfig
     * @return
     */
    public Integer getDispatchTimeout(List<DispatchConfig> dispatchConfig) {
        Integer rest = -1;
        if (CollectionUtils.isNotEmpty(dispatchConfig)) {
            Date currentDate = new Date();
            Integer dispatchTimeout = this.getDispatchTimeoutHandle(currentDate, dispatchConfig, DispatchConfig.DATETYPE_TWO);
            if (dispatchTimeout != null) {
                return dispatchTimeout;
            }
            int weekDay = DateUtil.getWeekDay(currentDate);
            // 是否命中 工作日
            boolean isWorkDay = weekDay != 6 && weekDay != 0;
            dispatchTimeout = this.getDispatchTimeoutHandle(currentDate, dispatchConfig, (isWorkDay ? DispatchConfig.DATETYPE_ZERO : DispatchConfig.DATETYPE_ONE));
            if (dispatchTimeout != null) {
                return dispatchTimeout;
            }
        }
        return rest;
    }

    /**
     * 校验时间 是否命中范围
     *
     * @param currentDate
     * @param startTimeStr 时间格式 HH:mm:ss
     * @param endTimeStr   时间格式 HH:mm:ss
     * @param formatTime   自定义时间格式
     * @return
     */
    public Boolean timeScoreVerify(Date currentDate, String startTimeStr, String endTimeStr, String formatTime) {
        if (StringUtils.isEmpty(startTimeStr) || StringUtils.isEmpty(endTimeStr) || StringUtils.isEmpty(formatTime)) {
            return Boolean.FALSE;
        }
        Date nowTime = DateUtil.convert2Date(currentDate, formatTime);
        Date startTime = DateUtil.convert2Date(startTimeStr, formatTime);
        Date endTime = DateUtil.convert2Date(endTimeStr, formatTime);

        if (nowTime.getTime() == startTime.getTime()
                || nowTime.getTime() == endTime.getTime()) {
            return true;
        }

        Calendar date = Calendar.getInstance();
        date.setTime(nowTime);

        Calendar begin = Calendar.getInstance();
        begin.setTime(startTime);

        Calendar end = Calendar.getInstance();
        end.setTime(endTime);

        if (date.after(begin) && date.before(end)) {
            return Boolean.TRUE;
        } else {
            return Boolean.FALSE;
        }

    }

    /**
     * 校验时间 是否命中范围
     *
     * @param currentDate
     * @param startTimeStr 时间格式 HH:mm:ss
     * @param endTimeStr   时间格式 HH:mm:ss
     * @return
     */
    private Boolean timeScoreVerify(Date currentDate, String startTimeStr, String endTimeStr) {
        return this.timeScoreVerify(currentDate, startTimeStr, endTimeStr, DateUtil.FORMAT_time);
    }

    /**
     * 获取配置
     *
     * @param currentDate
     * @param dispatchConfig
     * @param dateType
     * @return null 表示没有配置
     */
    private Integer getDispatchTimeoutHandle(Date currentDate, List<DispatchConfig> dispatchConfig, int dateType) {
        List<DispatchConfig> activityDayConfig = dispatchConfig.stream().filter(d -> d.getDateType() == dateType).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(activityDayConfig)) {
            for (DispatchConfig d : activityDayConfig) {
                if (dateType == DispatchConfig.DATETYPE_TWO) {
                    // null 默认当做没配置
                    if (Objects.isNull(d.getStartTime()) || Objects.isNull(d.getEndTime())) {
                        return null;
                    }
                    // 并且不在 活动日内
                    boolean isActivityDay = currentDate.after(d.getStartTime()) && currentDate.before(d.getEndTime());
                    if (!isActivityDay) {
                        return null;
                    }
                }
                Integer peakTime = this.getPeakTime(currentDate, d.getPeakTimeConfigList());
                if (Objects.nonNull(peakTime)) {
                    return peakTime;
                }
                // 在活动范围内, 没有命中高峰期
                return d.getDispatchTime();
            }
        }
        return null;
    }

    /**
     * 返回是否有高峰配置 , 没有就返回 null
     *
     * @param currentDate
     * @param peakTimeConfigList
     * @return
     */
    private Integer getPeakTime(Date currentDate, List<PeakTimeConfig> peakTimeConfigList) {
        if (CollectionUtils.isNotEmpty(peakTimeConfigList)) {
            for (PeakTimeConfig peakTimeConfig : peakTimeConfigList) {
                boolean isHit = this.timeScoreVerify(currentDate, peakTimeConfig.getStartTime(), peakTimeConfig.getEndTime());
                if (isHit) {
                    return peakTimeConfig.getDispatchTime();
                }
            }
        }
        return null;
    }

    /**
     * 是否商家自配送
     *
     * @param deliveryType
     * @return true 自配送
     */
    public boolean deliveryTypeSelf(String deliveryType) {
        return delivery_type_self.equalsIgnoreCase(deliveryType);
    }

    /**
     * 到店订单,出餐模式设置的 出餐时长
     *
     * @param businessInfo
     * @return
     */
    public Integer getPeakTimeDelivery(BusinessInfoDTO businessInfo) {
        Integer peakTimeDelivery = this.getPeakTimeDelivery(businessInfo.getExpandFields());
        if (Objects.nonNull(peakTimeDelivery)) {
            return peakTimeDelivery;
        }
        // 到店订单，门店接单 1:2小时;2:1小时;3:30分钟;4:15分钟;5:10分钟;6:5分钟
        Integer takeOrderWorkflowFinishTime = businessInfo.getAutoSelfmentionTakeOrderWorkflowFinishTime();
        if (Objects.isNull(takeOrderWorkflowFinishTime)) {
            return null;
        }
        switch (takeOrderWorkflowFinishTime) {
            case 1:
                return 120;
            case 2:
                return 60;
            case 3:
                return 30;
            case 4:
                return 15;
            case 5:
                return 10;
            case 6:
                return 5;
            default:
                return null;
        }
    }

    /**
     * 获取高峰时期的配置时间 是否命中
     *
     * @param expandFields
     * @return null标识没有命中高峰期配置时间
     */
    private Integer getPeakTimeDelivery(ExpandFieldsDTO expandFields) {
        List<PeakShipmentDTO> peakShipmentDTOList = expandFields.getPeakShipment();
        if (CollectionUtils.isEmpty(peakShipmentDTOList)) {
            return null;
        }
        Date currentDate = new Date();
        for (PeakShipmentDTO peakShipmentDTO : peakShipmentDTOList) {
            Boolean isHit = this.timeScoreVerify(currentDate, peakShipmentDTO.getStartTime(), peakShipmentDTO.getEndTime(), "HH:mm");
            if (isHit) {
                return Integer.valueOf(peakShipmentDTO.getCostMinute());
            }
        }
        return null;
    }
}
