package com.zm.order.tool.server.handler;

import com.alibaba.fastjson.JSON;
import com.github.dozermapper.core.Mapper;
import com.google.common.collect.Lists;
import com.zm.order.tool.server.builder.SearchRequestBuilder;
import com.zm.order.tool.server.constants.CommonConstants;
import com.zm.order.tool.server.dao.OrderAddrDao;
import com.zm.order.tool.server.dao.OrderItemDao;
import com.zm.order.tool.server.dao.RefundDao;
import com.zm.order.tool.server.dao.RefundItemDao;
import com.zm.order.tool.server.dto.OrderDTO;
import com.zm.order.tool.server.dto.RefundDTO;
import com.zm.order.tool.server.enums.BizTypeEnum;
import com.zm.order.tool.server.manager.OrderManager;
import com.zm.order.tool.server.manager.SearchManager;
import com.zm.order.tool.server.model.*;
import com.zm.order.tool.server.query.RefundQuery;
import com.zm.order.tool.server.query.SearchOrderQuery;
import com.zm.order.tool.server.response.InnerOrderDiscount;
import com.zm.order.tool.server.utils.DateUtils;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 * @Description 餐饮业务处理
 * @Author: ph
 * @Date: 2019/12/9 19:47
 */
@Component
public class CyBusinessHandler implements BusinessHandler {

    private static final Logger logger = LoggerFactory.getLogger(CyBusinessHandler.class);

    @Autowired
    private Mapper mapper;

    @Autowired
    private OrderItemDao orderItemDao;

    @Autowired
    private RefundDao refundDao;

    @Autowired
    private OrderManager orderManager;
    @Autowired
    private RefundItemDao refundItemDao;

    @Autowired
    private SearchManager searchManager;

    @Autowired
    private OrderAddrDao orderAddrDao;

    private static final String WALLET_AMOUNT = "wallet_amount";

    private static final String AMOUNT = "amount";

    private static final String RESERVE_TAKEOUT_TIME = "reserve_takeout_time";

    private static final String PRODUCTION_END_TIME = "productioned_time";

    private static final String USE_PLATFORM_PAYMENT = "use_platform_payment";

    private static final String RECEIPT = "receipt";

    private static final String TERMINAL_NUM = "terminalNum";

    private static final String RESERVE_TIME = "reserve_time";

    private static final String GROUP_STATUS = "group_status";

    private static final String GROUP_TYPE = "group_type";

    /**
     * 2020-7-14 查询预约单
     */
    private static final String SPECIFIC_RESERVE_TIME_SPLIT = ":";
    /**
     * 2020-7-14 查询预约单
     */

    private static final String RECEIVER_MOBILE = "receiverMobile";

    private static final String SYNC_ERP_ERROR = "sync_erp_error";

    private static final Integer ORDER_CLOSE_STATUS = 6;

    private static final Integer ORDER_COMPLETED_STATUS = 5;

    private static final Integer ORDER_PAYED_STATUS = 1;

    private static final Integer REFUND_COMPLETED_STATUS = 100;

    private static final Integer HAS_AFTER_SALE_STATUS = 1;

    private static final Integer LEGAL_RESERVE_TIME_LENGTH = 10;
    /**
     * 2020-7-14 查询预约单
     */

    private static final Integer SPECIFIC_RESERVE_TIME_LENGTH = 5;

    /**
     * 2020-7-14 查询预约单
     */

    @Override
    public Integer bizType() {
        return BizTypeEnum.CY.getType();
    }

    @Override
    public BaseIndexOrder buildIndexOrder(Order order) {
        CyIndexOrder indexOrder = mapper.map(order, CyIndexOrder.class);
        indexOrder.setOrderId(order.getId());
        buildPayInfo(order, indexOrder);
        buildPerformanceInfo(order, indexOrder);
        buildDiscountInfo(order, indexOrder);
        buildItemInfo(order, indexOrder);
        buildFeatures(order, indexOrder);
        buildRefundInfo(order, indexOrder);
        return indexOrder;
    }

    private void buildPayInfo(Order order, CyIndexOrder indexOrder) {
        try {
            indexOrder.setIsPay(Objects.isNull(order.getPayAt()) ? 0 : 1);
            if (!StringUtils.isEmpty(order.getPayInfo())) {
                Map<String, Object> payInfoMap = JSON.parseObject(order.getPayInfo(), Map.class);
                if (payInfoMap.containsKey(WALLET_AMOUNT)) {
                    indexOrder.setWalletAmount((Integer) payInfoMap.get(WALLET_AMOUNT));
                    indexOrder.setUseWallet((((Integer) payInfoMap.get(WALLET_AMOUNT) > 0 ? 1 : 0)));
                }
                if (payInfoMap.containsKey(AMOUNT)) {
                    indexOrder.setAmount((Integer) payInfoMap.get(AMOUNT));
                    indexOrder.setUseThird(((Integer) payInfoMap.get(AMOUNT) > 0 ? 1 : 0));
                }
                if (payInfoMap.containsKey(USE_PLATFORM_PAYMENT)) {
                    indexOrder.setUsePlatForm((Integer) payInfoMap.get(USE_PLATFORM_PAYMENT));
                }
            }
        } catch (Exception e) {
            logger.error("buildPayInfo failed! orderNo:{}, cause by:{}", order.getOrderNo(), e);
        }
    }

    private void buildPerformanceInfo(Order order, CyIndexOrder indexOrder) {
        try {
            indexOrder.setIsCompleted(Objects.isNull(order.getCompletedAt()) ? 0 : 1);
            String performanceInfo = order.getPerformanceInfo();
            if (!StringUtils.isEmpty(performanceInfo)) {
                Map<String, Object> performanceInfoMap = JSON.parseObject(performanceInfo, Map.class);
                if (performanceInfoMap.containsKey(RESERVE_TAKEOUT_TIME)) {
                    indexOrder.setIsReserveTakeoutTimeEmpty(StringUtils.isEmpty(performanceInfoMap.get(RESERVE_TAKEOUT_TIME)) ? 0 : 1);
                } else {
                    indexOrder.setIsReserveTakeoutTimeEmpty(0);
                }
                if (performanceInfoMap.containsKey(PRODUCTION_END_TIME)) {
                    indexOrder.setIsProductionEnd(StringUtils.isEmpty(performanceInfoMap.get(PRODUCTION_END_TIME)) ? 0 : 1);
                } else {
                    indexOrder.setIsProductionEnd(0);
                }
                if (performanceInfoMap.containsKey(RESERVE_TIME)) {
                    if (!StringUtils.isEmpty(performanceInfoMap.get(RESERVE_TIME))) {
                        String reserveTime = performanceInfoMap.get(RESERVE_TIME).toString();
                        if (reserveTime.length() > LEGAL_RESERVE_TIME_LENGTH) {
                            try {
                                Date date = DateUtils.parse(reserveTime, "yyyy-MM-dd HH:mm");
                                indexOrder.setReserveTime(date);
                            } catch (ParseException pe) {
                                logger.error("parse date failed, time:{}, orderNo:{}", reserveTime, order.getOrderNo());
                            }
                        }
                        if (reserveTime.length() == SPECIFIC_RESERVE_TIME_LENGTH && reserveTime.contains(SPECIFIC_RESERVE_TIME_SPLIT)) {
                            Date date = this.buildReserveTime(reserveTime, order.getOrderAt());
                            indexOrder.setReserveTime(date);
                        }
                    }
                }
                if (performanceInfoMap.containsKey(RECEIVER_MOBILE)) {
                    String receiverMobile = performanceInfoMap.get(RECEIVER_MOBILE).toString();
                    indexOrder.setReceiverMobile(receiverMobile);
                }
            } else {
                indexOrder.setIsReserveTakeoutTimeEmpty(0);
                indexOrder.setIsProductionEnd(0);
            }
        }catch (Exception e){
            logger.error("buildPerformanceInfo failed! orderNo:{}, cause by:{}", order.getOrderNo(), e);
        }

    }

    private Date buildReserveTime(String reserveTime, Date date) {
        try {
            SimpleDateFormat getDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            String format = getDateFormat.format(date);
            format = format + " " + reserveTime;
            SimpleDateFormat returnDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            Date parse = returnDateFormat.parse(format);
            return parse;
        } catch (ParseException e) {
            logger.error("buildReserveTime is filed  reserveTime{}", reserveTime);
            return null;
        }
    }

    private void buildDiscountInfo(Order order, CyIndexOrder indexOrder) {
        try {
            String discountInfo = order.getDiscountInfo();
            if (!StringUtils.isEmpty(discountInfo)) {
                List<InnerOrderDiscount> discountList = JSON.parseArray(discountInfo, InnerOrderDiscount.class);
                indexOrder.setDiscountTypeList(
                    discountList.stream().map(InnerOrderDiscount::getDiscountType).distinct().collect(toList()));
                indexOrder.setDiscountIdList(
                    discountList.stream().map(InnerOrderDiscount::getDiscountId).distinct().collect(toList()));
            }
        } catch (Exception e) {
            logger.error("buildDiscountInfo failed! orderNo:{}, cause by:{}", order.getOrderNo(), e);
        }
    }

    private void buildItemInfo(Order order, CyIndexOrder indexOrder) {
        try {
            String itemInfo = order.getItemInfo();
            if (!StringUtils.isEmpty(itemInfo)) {
                List<OrderItem> orderItemList;
                if (Objects.equals(itemInfo, CommonConstants.ITEM_FLAG)) {
                    orderItemList = orderItemDao.selectByOrderNo(indexOrder.getOrderNo(), indexOrder.getUserId());
                } else {
                    orderItemList = JSON.parseArray(itemInfo, OrderItem.class);
                }
                List<String> itemNameList = orderItemList.stream().map(OrderItem::getItemName).collect(toList());
                indexOrder.setActivityIdList(orderItemList.stream().map(OrderItem::getActivityId).distinct().collect(toList()));
            }
        }catch (Exception e){
            logger.error("buildItemInfo failed! orderNo:{}, cause by:{}", order.getOrderNo(), e);
        }

    }

    private void buildFeatures(Order order, CyIndexOrder indexOrder) {
        if (!StringUtils.isEmpty(order.getFeatures())) {
            Map<String, Object> extraMap = order.getExtraMap();
            if (extraMap.containsKey(RECEIPT)) {
                if (Objects.isNull(order.getIsReceipt()) || Objects.equals(order.getIsReceipt(), 0)) {
                    indexOrder.setIsReceipt((Integer) extraMap.get(RECEIPT));
                }
            }
            if (extraMap.containsKey(TERMINAL_NUM) && StringUtils.isEmpty(order.getReceiptTerminal())) {
                if (!StringUtils.isEmpty(extraMap.get(TERMINAL_NUM))) {
                    indexOrder.setReceiptTerminal((String) extraMap.get(TERMINAL_NUM));
                }
            }
            if (extraMap.containsKey(SYNC_ERP_ERROR)) {
                if (!StringUtils.isEmpty(extraMap.get(SYNC_ERP_ERROR))) {
                    indexOrder.setSyncErpError(Integer.valueOf(extraMap.get(SYNC_ERP_ERROR).toString()));
                }
            }
            if (extraMap.containsKey(GROUP_STATUS) && !StringUtils.isEmpty(extraMap.get(GROUP_STATUS))) {
                indexOrder.setGroupStatus(Integer.valueOf(extraMap.get(GROUP_STATUS).toString()));
            }
            if (extraMap.containsKey(GROUP_TYPE) && !StringUtils.isEmpty(extraMap.get(GROUP_TYPE))) {
                indexOrder.setGroupType(Integer.valueOf(extraMap.get(GROUP_TYPE).toString()));
            }
            List<String> searchList = new ArrayList<>();
            searchList.add(order.getOrderNo());
            // 用userId代替下单人手机号
            searchList.add(order.getUserId().toString());
            if (!StringUtils.isEmpty(order.getStoreOrderNo())) {
                searchList.add(order.getStoreOrderNo());
            }
            // 取餐人手机号
            if (!StringUtils.isEmpty(order.getMobile())) {
                searchList.add(order.getMobile());
            }
            // 收货人手机号
            OrderAddr orderAddr = orderAddrDao.selectByOrderNo(order.getOrderNo(), order.getUserId());
            if (Objects.nonNull(orderAddr) && !StringUtils.isEmpty(orderAddr.getMobile())) {
                searchList.add(orderAddr.getMobile());
            }
            indexOrder.setSearchList(searchList);
        }
    }

    private void buildRefundInfo(Order order, CyIndexOrder indexOrder) {
        // 设置是否退款完成
        indexOrder.setRefundCompleted(0);
        final boolean refundFlag1 = Objects.equals(order.getStatus(), ORDER_CLOSE_STATUS) && Objects.equals(order.getPayStatus(), ORDER_PAYED_STATUS);
        final boolean refundFlag2 = Objects.equals(order.getStatus(), ORDER_COMPLETED_STATUS) && Objects.equals(order.getPayStatus(), ORDER_PAYED_STATUS);
        final boolean refundFlag3 = Objects.equals(order.getAfterSaleStatus(), HAS_AFTER_SALE_STATUS) && Objects.equals(order.getPayStatus(), ORDER_PAYED_STATUS);
        if (refundFlag1 || refundFlag2 || refundFlag3) {
            RefundQuery refundQuery = new RefundQuery();
            refundQuery.setOrderNo(order.getOrderNo());
            List<Refund> refundList = refundDao.selectList(refundQuery);
            List<Integer> statusList = new ArrayList<>();
            if (!CollectionUtils.isEmpty(refundList)) {
                for (Refund refund : refundList) {
                    if (Objects.equals(refund.getStatus(), REFUND_COMPLETED_STATUS)) {
                        indexOrder.setRefundCompleted(1);
                    }
                    statusList.add(refund.getStatus());
                }
            }
            //存放退款单所有状态
            statusList = statusList.stream().distinct().collect(Collectors.toList());
            indexOrder.setRefundAllStatusList(statusList);
        }
    }

    @Override
    public SearchSourceBuilder buildSearchSourceBuilder(SearchOrderQuery searchOrderQuery) {
        SearchSourceBuilder searchSourceBuilder = SearchRequestBuilder.buildOrderSearchBuilder(searchOrderQuery);
        return searchSourceBuilder;
    }

    @Override
    public List<BaseIndexOrder> parseIndexOrder(SearchHit[] searchHits) {
        List<BaseIndexOrder> list = Lists.newArrayListWithCapacity(searchHits.length);
        for (int i = 0; i < searchHits.length; i++) {
            SearchHit searchHit = searchHits[i];
            CyIndexOrder t = JSON.parseObject(searchHit.getSourceAsString(), CyIndexOrder.class);
            t.setOrderId(Long.valueOf(searchHit.getId()));
            list.add(t);
        }
        return list;
    }

    @Override
    public Integer getRefundAmount(RefundDTO refundDTO) {
        return 0;
    }

    @Override
    public BaseIndexOrder getOrderDto(BaseIndexOrder baseIndexOrder, OrderDTO orderDTO, Order order) {
        CyIndexOrder cyIndexOrder = (CyIndexOrder)baseIndexOrder;
        return cyIndexOrder;
    }


}
