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.OrderItemDao;
import com.zm.order.tool.server.dao.OrderPayDetailsDao;
import com.zm.order.tool.server.dao.RefundDao;
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.model.*;
import com.zm.order.tool.server.query.SearchOrderQuery;
import org.elasticsearch.index.query.BoolQueryBuilder;
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.util.*;

/**
 * 新餐饮处理器
 * @author NianChang
 * @date 2021/03/02 9:55 上午
 */
@Component
@SuppressWarnings("all")
public class CateringBusinessHandler implements BusinessHandler {

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

    @Autowired
    private Mapper mapper;

    @Autowired
    private RefundDao refundDao;

    @Autowired
    private OrderItemDao orderItemDao;

    /**
     * 配送状态
     */
    private static final String DELIVERY_STATUS = "deliveryStatus";

    /**
     * 收货手机号
     */
    String RECEIVER_MOBILE = "receiverMobile";

    /**
     * 预约时间
     */
    String RESERVE_TIME = "reserveTime";

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

    /**
     * 支付状态
     */
    private static final Integer ORDER_PAY_STATUS = 1;

    /**
     * 桌位名称
     */
    private static final String SEAT_NAME = "seatName";

    /**
     * 同步ERP异常
     */
    private static final String SYNC_ERROR = "syncError";

    /**
     * 渠道码
     */
    private static final String CHANNEL_CODE = "channelCode";

    /**
     * 账单号
     */
    private static final String BILL_NO = "billNo";

    /**
     * 拼团状态
     */
    private static final String GROUP_STATUS = "groupStatus";

    @Autowired
    private OrderPayDetailsDao payDetailsDao;

    private static final String USE_WALLET = "useWallet";

    /**
     * 入账类型
     */
    String RECEIVE_PAYMENT_TYPE = "receivePaymentType";

    /**
     * 餐牌号
     */
    String MEAL_TAKING_DEVICE_NO = "mealTakingDeviceNo";

    /**
     * 商品订单类型
     */
    String GOODS_TYPE = "goodsSubType";

    /**
     * 雷达订单前缀
     */
    String RADAR_ORDER_SCRM = "scrm";
    /**
     * 实体储值卡类型
     */
    String DEPOSIT_ENTITY_BIZ_TYPE = "depositEntityBizType";

    /**
     * 推广码id
     */
    String ORDER_PROMOTE_CODE = "orderPromoteCode";

    /**
     * 扩展字段-企微员工id
     */
    String WORK_WECHAT_USERID = "workWechatUserid";

    /**
     * 拼团类型
     */
    private static final String GROUP_TYPE = "groupType";

    /**
     * 订单排队状态
     */
    String ORDER_LINE_UP_STATUS = "lineUpStatus";

    /**
     * 进排队时间
     */
    String QUEUE_TIME = "queueTime";

    /**
     * 企业订单信息
     */
    String EXTRA_ENTERPRISE_ORDER_INFO = "extraEnterpriseOrderInfo";

    /**
     * 企业订单id
     */
    String ENTERPRISE_ID = "enterpriseId";

    @Override
    public BaseIndexOrder buildIndexOrder(Order order) {
        CateringIndexOrder indexOrder = mapper.map(order, CateringIndexOrder.class);
        try {
            buildBaseInfo(indexOrder, order);
            buildItemInfo(indexOrder, order);
            buildExtInfo(indexOrder, order);
            buildExtInfo1(indexOrder, order);
            buildPerInfo(indexOrder, order);
            buildPayInfo(indexOrder, order);
            buildLikeSearch(indexOrder, order);
            buildAddressInfo(indexOrder, order);
        } catch (Exception e) {
            logger.error("CateringBusinessHandler[buildIndexOrder]failed! orderNo:{}, cause by:{}", order.getOrderNo(), e);
        }
        return indexOrder;
    }

    private void buildPayInfo(CateringIndexOrder indexOrder, Order order) {
        // 记录三方支付金额
        indexOrder.setAmount(Objects.nonNull(order.getPayAmount()) ? order.getPayAmount() : 0);
        try {
            setWalletAmount(indexOrder, order);
            setPayTypeList(indexOrder, order);
        } catch (Exception e) {
            logger.error("buildPayInfo[BUILD_PAY_AMOUNT_ERROR]failed! order:{}, cause by:{}", order, e);
        }
    }

    private void buildAddressInfo(CateringIndexOrder indexOrder, Order order) {
        try {
            if (!StringUtils.isEmpty(order.getAddrInfo())) {
                InnerOrderAddr orderAddr = JSON.parseObject(order.getAddrInfo(), InnerOrderAddr.class);
                indexOrder.setAcceptMobile(orderAddr.getMobile());
                indexOrder.setAcceptName(orderAddr.getAcceptName());
            }
        } catch (Exception e) {
            logger.error("CateringBusinessHandler[buildAddressInfo]failed! orderNo:{}, cause by:{}", order.getOrderNo(), e);
        }
    }

    private void setPayTypeList(CateringIndexOrder indexOrder, Order order) {
        List<OrderPayDetails> payDetailsList = this.parsePayList(order);
        List<Integer> payTypeList = new ArrayList<>(payDetailsList.size());
        if (!CollectionUtils.isEmpty(payDetailsList)) {
            for (OrderPayDetails payDetails : payDetailsList) {
                payTypeList.add(payDetails.getPayType());
            }
        }
        indexOrder.setPayTypeList(payTypeList);
    }

    private List<OrderPayDetails> parsePayList(Order order) {
        List<OrderPayDetails> payDetailsList;
        String payDetailInfo = order.getPayDetailInfo();
        if (!StringUtils.isEmpty(payDetailInfo) && !Objects.equals(payDetailInfo, CommonConstants.PAY_FLAG)) {
            payDetailsList = JSON.parseArray(payDetailInfo, OrderPayDetails.class);
        } else {
            payDetailsList = payDetailsDao.selectByOrderNo(order.getOrderNo(), order.getUserId());
        }
        return payDetailsList;
    }

    private void buildLikeSearch(CateringIndexOrder index, Order order) {
        List<String> likeSearch = new ArrayList<>(2);
        try {
            // 手机号截取后四位支持搜索
            String mobile = order.getMobile();
            if (!StringUtils.isEmpty(order.getMobile()) && !order.getMobile().equals("0")) {
                String suffix;
                if (mobile.contains(",")) {
                    int idx = mobile.indexOf(",");
                    suffix = mobile.substring(idx - 4, idx);
                } else {
                    suffix = mobile.substring(mobile.length() - 4);
                }
                likeSearch.add(suffix);
            }
            // 订单号截取后六位支持搜索
            if (!StringUtils.isEmpty(order.getOrderNo())) {
                likeSearch.add(order.getOrderNo().substring(order.getOrderNo().length() - 6));
            }
        } catch (Exception e) {
            logger.error("[buildLikeSearch]failed! order:{}, cause by:{}", order, e);
        }
        index.setLikeSearch(likeSearch);
    }

    private void setWalletAmount(CateringIndexOrder indexOrder, Order order) {
        String payInfo = order.getPayInfo();
        if (StringUtils.isEmpty(payInfo)) {
            return;
        }
        Map<String, Object> payInfoMap = JSON.parseObject(payInfo);
        if (Objects.isNull(payInfoMap.get(USE_WALLET))) {
            return;
        }
        Integer useWallet = Integer.valueOf(payInfoMap.get(USE_WALLET).toString());
        // 支付方式中存在余额支付
        Integer walletAmount = 0;
        if (Objects.equals(1, useWallet)) {
            List<OrderPayDetails> payDetailsList;
            String payDetailInfo = order.getPayDetailInfo();
            if (!StringUtils.isEmpty(payDetailInfo) && !Objects.equals(payDetailInfo, CommonConstants.ITEM_FLAG)) {
                payDetailsList = JSON.parseArray(payDetailInfo, OrderPayDetails.class);
            } else {
                payDetailsList = payDetailsDao.selectByOrderNo(order.getOrderNo(), order.getUserId());
            }
            if (!CollectionUtils.isEmpty(payDetailsList)) {
                for (OrderPayDetails payDetails : payDetailsList) {
                    // payType = 4 余额支付
                    if (Objects.equals(payDetails.getPayType(), 4)) {
                        walletAmount = payDetails.getAmount();
                        break;
                    }
                }
            }
        }
        indexOrder.setSearchWalletAmount(walletAmount);
    }

    private void buildPerInfo(CateringIndexOrder indexOrder, Order order) {
        if (!StringUtils.isEmpty(order.getPerformanceInfo())) {
            Map<String, Object> performanceMap = JSON.parseObject(order.getPerformanceInfo());
            if (!CollectionUtils.isEmpty(performanceMap)) {
                if (Objects.nonNull(performanceMap.get(DELIVERY_STATUS))) {
                    indexOrder.setDeliveryStatus(Integer.valueOf(performanceMap.get(DELIVERY_STATUS).toString()));
                }
                if (!StringUtils.isEmpty(performanceMap.get(RECEIVER_MOBILE))) {
                    String receiverMobile = performanceMap.get(RECEIVER_MOBILE).toString();
                    indexOrder.setReceiverMobile(receiverMobile);
                }
                if (!StringUtils.isEmpty(performanceMap.get(RESERVE_TIME))) {
                    String reserveTime = performanceMap.get(RESERVE_TIME).toString();
                    try {
                        Date date = new Date();
                        date.setTime(Long.parseLong(reserveTime));
                        indexOrder.setReserveTime(date);
                    } catch (Throwable ex) {
                        logger.error("CateringBusinessHandler[buildPerInfoError] time:{} orderNo:{}, cause by:{}",
                                reserveTime, order.getOrderNo(), ex);
                    }
                }
            }
        }
    }

    private void buildBaseInfo(CateringIndexOrder indexOrder, Order order) {
        indexOrder.setOrderId(order.getId());
        indexOrder.setRefundCompleted(0);
        if (Objects.nonNull(order.getActualAmount())) {
            indexOrder.setSearchActualAmount(order.getActualAmount());
        }
        if (checkStatus(order.getPayStatus())) {
            try {
                indexOrder.setRefundCompleted(order.getRefundFlag());
            } catch (Exception e) {
                logger.error("[SELECT_REFUND_ID_LIST]failed! cause by:{}", e);
            }
        }
        indexOrder.setSearchPayer(order.getPayer());
        if (Objects.nonNull(order.getCompletedAt())) {
            indexOrder.setSearchCompletedAt(order.getCompletedAt());
        }
    }

    private void buildItemInfo(CateringIndexOrder indexOrder, Order order) {
        List<OrderItem> itemList = this.getItemList(order);
        List<String> searchCondition = new ArrayList<>();
        this.parseItemAttribute(indexOrder, itemList, searchCondition);
        this.setSearchAttribute(indexOrder, order, searchCondition);
    }

    /**
     * 解析商品属性赋值
     *
     * <p>
     *      获取商品type支持检索
     *      获取商品名称、itemId支持检索
     * </p>
     *
     * @param index	ES mapping文档
     * @param itemList 商品列表
     * @param searchCondition 全局搜索条件
     */
    private void parseItemAttribute(CateringIndexOrder index, List<OrderItem> itemList, List<String> searchCondition) {
        if (CollectionUtils.isEmpty(itemList)) {
            return;
        }
        final int size = itemList.size();
        Set<Integer> itemTypeSet = new HashSet<>(size);
        Set<String> itemIdList = new HashSet<>(size);
        Set<String> itemNameList = new HashSet<>(size);
        Set<String> itemBarcodeList = new HashSet<>(size);
        for (OrderItem item : itemList) {
            if (!StringUtils.isEmpty(item.getItemName())) {
                itemNameList.add(item.getItemName());
                searchCondition.add(item.getItemName());
            }
            if (Objects.nonNull(item.getItemId())) {
                itemIdList.add(item.getItemId());
                searchCondition.add(item.getItemId());
            }
            if (Objects.nonNull(item.getItemType())) {
                itemTypeSet.add(item.getItemType());
            }
            if (!StringUtils.isEmpty(item.getItemBarcode())) {
                itemBarcodeList.add(item.getItemBarcode());
            }
        }

        index.setItemIdList(Lists.newArrayList(itemIdList));
        index.setItemBarcodeList(Lists.newArrayList(itemBarcodeList));
        index.setItemTypeList(Lists.newArrayList(itemTypeSet));
        index.setItemNamesKeyword(Lists.newArrayList(itemNameList));
    }

    /**
     * 全局搜索
     *
     * <p>
     *      多个条件拼接在一起，用','分割，多条件精准搜索
     *      现有条件：订单号、手机号、取餐号、三方单号、商品名称、商品id、桌台号
     *      后续可能还会增加
     * </p>
     *
     * @param indexOrder ES mapping文档
     * @param order 订单详情
     * @param searchCondition 全局搜索条件
     */
    private void setSearchAttribute(CateringIndexOrder indexOrder, Order order, List<String> searchCondition) {
        searchCondition.add(order.getMobile());
        searchCondition.add(order.getOrderNo());
        if (!StringUtils.isEmpty(order.getSourceNo())) {
            searchCondition.add(order.getSourceNo());
        }
        if (!StringUtils.isEmpty(order.getStoreOrderNo())) {
            searchCondition.add(order.getStoreOrderNo());
        }
        indexOrder.setGlobalSearch(String.join(",", searchCondition));
    }


    private List<OrderItem> getItemList(Order order) {
        List<OrderItem> itemList;
        if (StringUtils.isEmpty(order.getItemInfo()) || Objects.equals(CommonConstants.ITEM_FLAG, order.getItemInfo())) {
            itemList = orderItemDao.selectByOrderNo(order.getOrderNo(), order.getUserId());
        } else {
            itemList = JSON.parseArray(order.getItemInfo(), OrderItem.class);
        }
        return itemList;
    }

    private void buildExtInfo(CateringIndexOrder indexOrder, Order order) {
        Map<String, Object> extraMap = order.getExtraMap();
        if (!CollectionUtils.isEmpty(extraMap)) {
            if (!StringUtils.isEmpty(extraMap.get(SEAT_NAME))) {
                String seatName = extraMap.get(SEAT_NAME).toString();
                indexOrder.setSeatName(seatName);
                String globalSearch = indexOrder.getGlobalSearch();
                if (StringUtils.isEmpty(globalSearch)) {
                    globalSearch = seatName;
                } else {
                    globalSearch = globalSearch + "," + seatName;
                }
                indexOrder.setGlobalSearch(globalSearch);
            }
            if (Objects.nonNull(extraMap.get(SYNC_ERROR))) {
                indexOrder.setSyncErpError(Integer.valueOf(extraMap.get(SYNC_ERROR).toString()));
            }
            if (!StringUtils.isEmpty(extraMap.get(GROUP_STATUS))) {
                indexOrder.setGroupStatus(extraMap.get(GROUP_STATUS).toString());
            }
            if (Objects.nonNull(extraMap.get(GROUP_TYPE))) {
                indexOrder.setGroupType(Integer.valueOf(extraMap.get(GROUP_TYPE).toString()));
            }
            if (!StringUtils.isEmpty(extraMap.get(CHANNEL_CODE))) {
                indexOrder.setChannelCode(extraMap.get(CHANNEL_CODE).toString());
            }
            if (Objects.nonNull(extraMap.get(RECEIVE_PAYMENT_TYPE))) {
                indexOrder.setReceivePaymentType(Integer.valueOf(extraMap.get(RECEIVE_PAYMENT_TYPE).toString()));
            }
            if (Objects.nonNull(extraMap.get(GOODS_TYPE))) {
                indexOrder.setGoodsSubType(Integer.valueOf(extraMap.get(GOODS_TYPE).toString()));
            }
            if (!StringUtils.isEmpty(extraMap.get(BILL_NO))) {
                indexOrder.setBillNo(extraMap.get(BILL_NO).toString());
            }
            if (!StringUtils.isEmpty(extraMap.get(MEAL_TAKING_DEVICE_NO))) {
                String globalSearch = indexOrder.getGlobalSearch();
                indexOrder.setGlobalSearch(globalSearch + "," + extraMap.get(MEAL_TAKING_DEVICE_NO));
            }
            if (extraMap.get(ORDER_LINE_UP_STATUS) != null) {
                indexOrder.setLineUpStatus(Integer.valueOf(extraMap.get(ORDER_LINE_UP_STATUS).toString()));
            }
            if (extraMap.get(QUEUE_TIME) != null) {
                indexOrder.setSearchQueueTime(new Date(Long.parseLong(extraMap.get(QUEUE_TIME).toString())));
            }
            if (Objects.nonNull(extraMap.get(EXTRA_ENTERPRISE_ORDER_INFO))) {
                Map<String, Object> infoMap = JSON.parseObject(extraMap.get(EXTRA_ENTERPRISE_ORDER_INFO).toString());
                if (Objects.nonNull(infoMap.get(ENTERPRISE_ID))) {
                    indexOrder.setEnterpriseId(infoMap.get(ENTERPRISE_ID).toString());
                }
            }
            if (!StringUtils.isEmpty(extraMap.get(CHANNEL_CODE))) {
                String channelCode = extraMap.get(CHANNEL_CODE).toString();
                if (channelCode.startsWith(RADAR_ORDER_SCRM)) {
                    indexOrder.setRadarOrder(1);
                }
            }
            Object depositEntityBizType = extraMap.get(DEPOSIT_ENTITY_BIZ_TYPE);
            if (Objects.nonNull(depositEntityBizType)) {
                indexOrder.setDepositEntityBizType(Integer.valueOf(depositEntityBizType.toString()));
            }
        }
    }

    private void buildExtInfo1(CateringIndexOrder indexOrder, Order order){
        Map<String, Object> extraMap = order.getExtraMap();
        if (!CollectionUtils.isEmpty(extraMap)) {
            if (!StringUtils.isEmpty(extraMap.get(ORDER_PROMOTE_CODE))) {
                indexOrder.setOrderPromoteCode(extraMap.get(ORDER_PROMOTE_CODE).toString());
            }
            if (!StringUtils.isEmpty(extraMap.get(ORDER_PROMOTE_CODE))) {
                indexOrder.setOrderPromoteCode(extraMap.get(ORDER_PROMOTE_CODE).toString());
            }
            if (!StringUtils.isEmpty(extraMap.get(WORK_WECHAT_USERID))) {
                indexOrder.setWorkWechatUserId(extraMap.get(WORK_WECHAT_USERID).toString());
            }
        }
    }

    /**
     * 校验订单可能存在退款单
     * @param payStatus
     * @return: boolean
     * @Date:   2020/5/12 6:03 PM
     */
    private boolean checkStatus(Integer payStatus) {
        if (Objects.equals(payStatus, ORDER_PAY_STATUS)) {
            return true;
        }
        return false;
    }

    @Override
    public SearchSourceBuilder buildSearchSourceBuilder(SearchOrderQuery searchOrderQuery) {
        SearchSourceBuilder searchSourceBuilder = SearchRequestBuilder.buildOrderSearchBuilder(searchOrderQuery);
        BoolQueryBuilder boolQueryBuilder = (BoolQueryBuilder) searchSourceBuilder.query();
        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];
            CateringIndexOrder t = JSON.parseObject(searchHit.getSourceAsString(), CateringIndexOrder.class);
            list.add(t);
        }
        return list;
    }

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

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

}
