package com.zm.order.tool.server.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.dozermapper.core.Mapper;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.zm.order.tool.server.builder.AdminBuilder;
import com.zm.order.tool.server.component.ShardingKeyGenerator;
import com.zm.order.tool.server.convert.AdminOrderConverter;
import com.zm.order.tool.server.dao.*;
import com.zm.order.tool.server.dto.*;
import com.zm.order.tool.server.enums.RefundLevelEnum;
import com.zm.order.tool.server.helper.AdminHelper;
import com.zm.order.tool.server.manager.CommonManager;
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.*;
import com.zm.order.tool.server.service.AdminOrderService;
import com.zm.order.tool.server.service.ExceptionConstants;
import com.zm.order.tool.server.service.OrderSyncService;
import com.zm.util.dto.ExceptionInfo;
import com.zm.util.dto.Result;
import org.apache.lucene.util.NamedThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.*;

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


/**
 * 管路员订单操作
 *
 * @Author 陈标
 * @Date 2019/12/20 13:46
 */
@Service
public class AdminOrderServiceImpl implements AdminOrderService, InitializingBean {

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

    public static int flag = 1;

    @Autowired
    private OrderDao orderDao;
    @Autowired
    private OrderItemDao orderItemDao;
    @Autowired
    private OrderDiscountDao orderDiscountDao;
    @Autowired
    private LineUpRecordDao lineUpRecordDao;
    @Autowired
    private AdminHelper helper;
    @Autowired
    private OrderSyncService orderSyncService;
    @Autowired
    private SearchManager searchManager;
    @Autowired
    private OrderOperationDao orderOperationDao;
    @Autowired
    private AdminOrderConverter converter;
    @Autowired
    private Mapper mapper;
    @Autowired
    private ToolInterfaceDao toolInterfaceDao;
    @Autowired
    private RefundDao refundDao;
    @Autowired
    private RefundItemDao refundItemDao;
    @Autowired
    private OrderIndexDao orderIndexDao;
    @Autowired
    private OrderStatusFlowsDao flowsDao;
    @Autowired
    private AdminBuilder adminBuilder;

    @Autowired
    private CommonManager commonManager;

    @Autowired
    private OrderManager orderManager;

    private ExecutorService executorService;

    private BlockingQueue workQueue;

    @Autowired
    private OrderSyncErrorDao orderSyncErrorDao;

    @Autowired
    private LunBoDao lunBoDao;

    @Autowired
    private ShardingKeyGenerator keyGenerator;

    @Override
    public Result orderSync(AdminOrderQuery query) {
        Result result = new Result<>();
        try {
            ExceptionInfo exceptionInfo = helper.checkOrderSync(query);
            if (ExceptionConstants.OK != exceptionInfo) {
                result.setException(exceptionInfo);
                return result;
            }
            OrderIndex orderIndex = orderIndexDao.selectOne(query.getOrderNo());
            if (Objects.isNull(orderIndex)) {
                result.setException(ExceptionConstants.ORDER_NO_INDEX_NOT_EXISTS);
                return result;
            }
            Order order = orderDao.selectByOrderNo(orderIndex.getOrderNo(), orderIndex.getUserId());
            if (Objects.isNull(order)) {
                result.setException(ExceptionConstants.ORDER_NOT_EXISTS);
                return result;
            }
            Result sync = orderSyncService.sync(order.getOrderNo(), order.getUserId(), null);
            if (!sync.isStatus()) {
                result.setException(sync.exceptionInfo());
                return result;
            }
            result.setStatus(true);
        } catch (Throwable throwable) {
            logger.error("AdminOrderImpl[orderSync] failed, request:{}, cause by:{}",
                    query.toString(), Throwables.getStackTraceAsString(throwable));
            result.setException(ExceptionConstants.SYSTEM_ERROR);
        }
        return result;
    }

    @Override
    public Result<List<String>> listOrderSync(AdminOrderQuery query) {
        Result<List<String>> result = new Result<>();
        List<String> fileOrderNoList = new ArrayList<>();
        try {
            ExceptionInfo exceptionInfo = helper.checkListOrderSync(query);
            if (ExceptionConstants.OK != exceptionInfo) {
                result.setException(exceptionInfo);
                return result;
            }
            List<String> orderNoList = query.getOrderNoList();
            for (String s : orderNoList) {
                OrderIndex orderIndex = orderIndexDao.selectOne(s);
                if (Objects.isNull(orderIndex)) {
                    fileOrderNoList.add(s);
                    continue;
                }
                Order order = orderDao.selectByOrderNo(orderIndex.getOrderNo(), orderIndex.getUserId());
                if (Objects.isNull(order)) {
                    fileOrderNoList.add(s);
                    continue;
                }
                Result sync = orderSyncService.sync(order.getOrderNo(), order.getUserId(), null);
                if (!sync.isStatus()) {
                    fileOrderNoList.add(s);
                }
            }
            result.setData(fileOrderNoList);
            result.setStatus(true);
        } catch (Throwable throwable) {
            logger.error("AdminOrderImpl[listOrderSync] failed, request:{}, cause by:{}",
                    query.toString(), Throwables.getStackTraceAsString(throwable));
            result.setException(ExceptionConstants.SYSTEM_ERROR);
        }
        return result;
    }

    @Override
    public Result<List<OrderOperateDTO>> getListOrderOperate(OrderOperationQuery query) {
        Result<List<OrderOperateDTO>> result = new Result<>();
        try {
            ExceptionInfo exceptionInfo = helper.checkOrderOperationQueryParam(query);
            if (ExceptionConstants.OK != exceptionInfo) {
                result.setException(exceptionInfo);
                return result;
            }
            OrderOperationQuery orderOperationQuery = mapper.map(query, OrderOperationQuery.class);
            List<OrderOperation> orderOperations = orderOperationDao.selectList(orderOperationQuery);
            List<OrderOperateDTO> orderOperateList = converter.convertOrderOperationDTO(orderOperations);
            result.setData(orderOperateList);
            result.setStatus(true);
            logger.info("response:{}", orderOperateList.toString());
        } catch (Throwable throwable) {
            logger.error("AdminOrderImpl[getListOrderOperate] failed, request:{}, cause by:{}",
                    query.toString(), Throwables.getStackTraceAsString(throwable));
            result.setException(ExceptionConstants.SYSTEM_ERROR);
        }
        return result;
    }

    @Override
    public Result<Integer> searchOrderCount(SearchOrderQuery searchOrderQuery) {
        Result<Integer> result = new Result<>();
        try {
            // 1.参数校验
            ExceptionInfo exceptionInfo = helper.checkSearchOrderCountParam(searchOrderQuery);
            if (ExceptionConstants.OK != exceptionInfo) {
                result.setException(exceptionInfo);
                return result;
            }
            // 2.查询数据
            int count = searchManager.countOrder(searchOrderQuery);
            // 3.组装返回
            result.setData(count);
            result.setStatus(true);
        } catch (Throwable throwable) {
            logger.error("AdminOrderImpl[countSearchOrder] failed, request:{}, cause by:{}",
                    searchOrderQuery.toString(), Throwables.getStackTraceAsString(throwable));
            result.setException(ExceptionConstants.SYSTEM_ERROR);
        }
        return result;
    }


    @Override
    public Result<List<LineUpRecordDTO>> searchLineUpRecordOrder(AdminOrderItemQuery adminOrderItemQuery) {
        Result<List<LineUpRecordDTO>> result = new Result<>();
        try {
            // 1.参数校验
            ExceptionInfo exceptionInfo = helper.checkGetAdminOrderIndexParam(adminOrderItemQuery);
            if (ExceptionConstants.OK != exceptionInfo) {
                result.setException(exceptionInfo);
                return result;
            }
            // 2.查询数据
            Result<List<BaseIndexOrder>> getResult = helper.getBaseIndexOrders(adminOrderItemQuery);
            if (!getResult.isStatus()) {
                result.setException(getResult.exceptionInfo());
                return result;
            }
            BaseIndexOrder baseIndexOrder = getResult.getData().get(0);
            // 第一次查是否有此订单排队记录
            LineUpRecordQuery firstLineUpRecordQuery = helper.buildLineUpRecordQuery(baseIndexOrder);
            List<LineUpRecord> lineUpRecords = lineUpRecordDao.selectList(firstLineUpRecordQuery);
            if (CollectionUtils.isEmpty(lineUpRecords)) {
                result.setException(ExceptionConstants.ORDER_NOT_LINEUP);
                return result;
            }
            LineUpRecord lineUpRecord = lineUpRecords.get(0);
            if (!Objects.equals(lineUpRecord.getIsDeleted(), 1)) {
                result.setException(ExceptionConstants.ORDER_NOT_COMPLETED);
                return result;
            }
            List<LineUpRecordDTO> list = helper.buildLineUpDto(lineUpRecords);
            result.setData(list);
            result.setStatus(true);
        } catch (Throwable throwable) {
            logger.error("AdminOrderImpl[searchOrderSimple] failed, request:{}, cause by:{}",
                    adminOrderItemQuery.toString(), Throwables.getStackTraceAsString(throwable));
            result.setException(ExceptionConstants.SYSTEM_ERROR);
        }
        return result;

    }

    @Override
    public Result<Long> createToolInterface(ToolInterfaceDTO toolInterfaceDTO) {
        Result<Long> result = new Result<>();
        try {
            // 1.参数校验
            ExceptionInfo exceptionInfo = helper.checkCreateToolInterface(toolInterfaceDTO);
            if (ExceptionConstants.OK != exceptionInfo) {
                result.setException(exceptionInfo);
                return result;
            }
            ToolInterface toolInterface = mapper.map(toolInterfaceDTO, ToolInterface.class);
            if (Objects.nonNull(toolInterface.getId())) {
                toolInterfaceDao.update(toolInterface);
            } else {
                toolInterface = helper.buildToolInterface(toolInterface);
                toolInterfaceDao.insert(toolInterface);
            }
            result.setData(toolInterface.getId());
            result.setStatus(true);
            return result;
        } catch (Throwable throwable) {
            logger.error("AdminOrderImpl[createToolInterface] failed, request:{}, cause by:{}",
                    toolInterfaceDTO.toString(), Throwables.getStackTraceAsString(throwable));
            result.setException(ExceptionConstants.SYSTEM_ERROR);
        }
        return result;
    }

    @Override
    public Result<List<ToolInterfaceDTO>> listToolInterface() {
        Result<List<ToolInterfaceDTO>> result = new Result<>();
        try {
            List<ToolInterface> toolInterfaces = toolInterfaceDao.selectList();
            if (CollectionUtils.isEmpty(toolInterfaces)) {
                result.setData(Collections.EMPTY_LIST);
                return result;
            }
            List<ToolInterfaceDTO> list = helper.buildToolInterfaceDTO(toolInterfaces);
            result.setData(list);
            result.setStatus(true);
            return result;
        } catch (Throwable throwable) {
            logger.error("AdminOrderImpl[createToolInterface] failed, request:{}, cause by:{}",
                    Throwables.getStackTraceAsString(throwable));
            result.setException(ExceptionConstants.SYSTEM_ERROR);
        }
        return result;

    }


    @Override
    public Result<List<RefundDetailDTO>> getRefundDetail(RefundQuery query) {
        Result<List<RefundDetailDTO>> result = new Result<>();
        try {
            // 1.参数校验
            ExceptionInfo exceptionInfo = helper.checkGetRefundDetailParam(query);
            if (ExceptionConstants.OK != exceptionInfo) {
                result.setException(exceptionInfo);
                return result;
            }
            // 2.查询数据
            List<Refund> refundList = refundDao.selectList(query);
            if (CollectionUtils.isEmpty(refundList)) {
                result.setData(Collections.EMPTY_LIST);
                result.setStatus(true);
                return result;
            }
            List<RefundDetailDTO> refundDetailDtoList = Lists.newArrayListWithCapacity(refundList.size());
            refundList.forEach(refund -> {
                if (Objects.equals(refund.getRefundLevel(), RefundLevelEnum.ITEM.getLevel())) {
                    RefundItemQuery refundItemQuery = new RefundItemQuery();
                    refundItemQuery.setRefundNo(refund.getRefundNo());
                    List<RefundItem> refundItemList = refundItemDao.selectList(refundItemQuery);
                    RefundDetailDTO refundDetailDTO = helper.convertByRefundItemList(refund, refundItemList);
                    refundDetailDtoList.add(refundDetailDTO);
                } else {
                    OrderIndex orderIndex = orderIndexDao.selectOne(refund.getOrderNo());
                    List<OrderItem> orderItemList = orderItemDao.selectByOrderNo(refund.getOrderNo(), orderIndex.getUserId());
                    RefundDetailDTO refundDetailDTO = helper.convertByOrderItemList(refund, orderItemList);
                    refundDetailDtoList.add(refundDetailDTO);
                }
            });
            // 3.组装返回
            result.setData(refundDetailDtoList);
            result.setStatus(true);
        } catch (Throwable throwable) {
            logger.error("RefundReadServiceImpl[getRefundDetail] failed, request:[refundNo:{}], cause by:{}",
                    query, Throwables.getStackTraceAsString(throwable));
            result.setException(ExceptionConstants.SYSTEM_ERROR);
        }
        return result;
    }

    @Override
    public Result<List<OrderSimpleDTO>> searchLineUpRecOrder(AdminOrderItemQuery adminOrderItemQuery) {
        Result<List<OrderSimpleDTO>> result = new Result<>();
        try {
            // 1.参数校验
            ExceptionInfo exceptionInfo = helper.checkGetAdminOrderIndexParam(adminOrderItemQuery);
            if (ExceptionConstants.OK != exceptionInfo) {
                result.setException(exceptionInfo);
                return result;
            }
            // 2.查询数据
            Result<List<BaseIndexOrder>> getResult = helper.getBaseIndexOrders(adminOrderItemQuery);
            if (!getResult.isStatus()) {
                result.setException(getResult.exceptionInfo());
                return result;
            }
            BaseIndexOrder baseIndexOrder = getResult.getData().get(0);
            // 构建订单所在的门店
            LineUpRecordQuery firstLineUpRecordQuery = helper.buildLineUpRecordOrderQuery(baseIndexOrder);
            List<LineUpRecord> lineUpRecords = lineUpRecordDao.selectList(firstLineUpRecordQuery);
            if (CollectionUtils.isEmpty(lineUpRecords)) {
                result.setException(ExceptionConstants.STORE_NOT_ORDER);
            }
            List<String> orderNoList = lineUpRecords.stream().map(LineUpRecord::getOrderNo).distinct().collect(toList());
            adminOrderItemQuery = helper.buildAdminOrderItemQuery(adminOrderItemQuery, orderNoList);
            Result<List<BaseIndexOrder>> baseIndexOrders = helper.getBaseIndexOrders(adminOrderItemQuery);
            if (!baseIndexOrders.isStatus()) {
                result.setException(getResult.exceptionInfo());
                return result;
            }
            List<OrderSimpleDTO> orderSimples = helper.buildOrderSimple(baseIndexOrders.getData());
            result.setStatus(true);
            result.setData(orderSimples);
        } catch (Throwable throwable) {
            logger.error("AdminOrderImpl[searchLineUpRecOrder] failed, request:{}, cause by:{}",
                    Throwables.getStackTraceAsString(throwable));
            result.setException(ExceptionConstants.SYSTEM_ERROR);

        }
        return result;
    }


    @Override
    public Result<UpdateCompletedAtDTO> updateOrderCompletedAt(OrderQuery query) {
        Result<UpdateCompletedAtDTO> result = new Result();
        UpdateCompletedAtDTO updateCompletedAtDTO = new UpdateCompletedAtDTO();
        // 1.参数校验
        try {
            logger.info("query{}", query.toString());
            ExceptionInfo exceptionInfo = helper.checkUpdateOrderCompletedAtParam(query);
            if (ExceptionConstants.OK != exceptionInfo) {
                result.setException(exceptionInfo);
                return result;
            }
            // 处理订单 空格问题
            query = helper.buildOrderNo(query);
            logger.info("orderNoList{}", query.getOrderNoList());
            List<String> unProcessed = query.getOrderNoList();
            List<BaseIndexOrder> baseIndexOrders = helper.ListBaseIndexOrder(query.getOrderNoList());
            if (CollectionUtils.isEmpty(baseIndexOrders)) {
                result.setException(ExceptionConstants.ORDER_NOT_EXISTS);
                return result;
            }
            for (BaseIndexOrder baseIndexOrder : baseIndexOrders) {
                if (Objects.equals(baseIndexOrder.getStatus(), 5)) {
                    logger.info("orderNo:{} already handled", baseIndexOrder.getOrderNo());
                    unProcessed.remove(baseIndexOrder.getOrderNo());
                    continue;
                }
                logger.info("baseIndexOrders{}", baseIndexOrders.toString());
                orderDao.updateCompletedAt(baseIndexOrder.getOrderId(), baseIndexOrder.getUserId());
                OrderOperation orderOperation = adminBuilder.buildOrderOperation(baseIndexOrder);
                orderOperationDao.insert(orderOperation);
                unProcessed.remove(baseIndexOrder.getOrderNo());
            }
            List<String> processed = baseIndexOrders.stream().map(BaseIndexOrder::getOrderNo).collect(toList());
            updateCompletedAtDTO.setProcessed(processed);
            updateCompletedAtDTO.setUnpProcessed(unProcessed);
            result.setData(updateCompletedAtDTO);
            result.setStatus(true);
        } catch (Throwable throwable) {
            logger.error("AdminOrderImpl[updateOrderCompletedAt] failed, request:{}, cause by:{}",
                    Throwables.getStackTraceAsString(throwable));
            result.setException(ExceptionConstants.SYSTEM_ERROR);

        }
        return result;
    }

    @Override
    public Result updateRefund(OrderQuery orderQuery) {
        Result result = new Result();
        try {
            List<String> orderNoList = Lists.newArrayList(orderQuery.getOrderNoList());
            RefundQuery refundQuery = new RefundQuery();
            refundQuery.setOrderNoList(orderQuery.getOrderNoList());
            List<Refund> refundList = refundDao.selectList(refundQuery);
            if (!CollectionUtils.isEmpty(refundList)) {
                refundList.forEach(refund -> {
                    Refund update = new Refund();
                    update.setId(refund.getId());
                    update.setStatus(103);
                    Map<String, Object> extraMap = refund.getExtraMap();
                    extraMap.put("deny_reason", "已备餐");
                    update.setExtraMap(extraMap);
                    refundDao.update(update);
                    orderNoList.remove(refund.getOrderNo());
                });
            }
            if (!CollectionUtils.isEmpty(orderNoList)) {
                orderNoList.forEach(orderNo -> {
                    logger.info("not handle orderNo:{}", orderNo);
                });
            }
            result.setStatus(true);
        } catch (Throwable throwable) {
            logger.error("AdminOrderImpl[updateRefund] failed, request:{}, cause by:{}",
                    Throwables.getStackTraceAsString(throwable));
            result.setException(ExceptionConstants.SYSTEM_ERROR);
        }
        return result;
    }

    @Override
    public Result deleteToolInterface(Long id) {
        Result result = new Result<>();
        try {
            ExceptionInfo exceptionInfo = helper.checkDeleteToolInterfaceParam(id);
            if (ExceptionConstants.OK != exceptionInfo) {
                result.setException(exceptionInfo);
                return result;
            }
            toolInterfaceDao.delete(id);
            result.setStatus(true);
        } catch (Throwable throwable) {
            logger.error("AdminOrderImpl[deleteToolInterface] failed, request:{}, cause by:{}",
                    id, Throwables.getStackTraceAsString(throwable));
            result.setException(ExceptionConstants.SYSTEM_ERROR);
        }
        return result;

    }

    @Override
    public Result clearEs(Long startTime, Integer time) {
        Result result = new Result<>();
        try {
            /*Long millNow = System.currentTimeMillis();
            // 遍历查询es，判断需要更新的，更新掉指定字段
            SearchOrderQuery searchOrderQuery = new SearchOrderQuery();
            searchOrderQuery.setSearchAfter(true);
            searchOrderQuery.setSize(200);
            // 从开始时间往后1天天增加
            long start = startTime;
            // 加到这个日期结束
            long end = 1594137848000L;
            while (start < end && (System.currentTimeMillis() - millNow) < (time * 1000) && (flag == 1) ) {
                Date orderAtStartDate = new Date(start);
                logger.info("startDate：" + orderAtStartDate);
                long orderAtEnd = start + 86400000L;
                Date orderAtEndDate = new Date(orderAtEnd);
                logger.info("endDate：" + orderAtEndDate);
                searchOrderQuery.setOrderAtStart(orderAtStartDate);
                searchOrderQuery.setOrderAtEnd(orderAtEndDate);
                boolean isStop = false;
                long copyStartId = 0;
                while (!isStop && (flag == 1)) {
                    searchOrderQuery.setLastId(copyStartId);
                    long l1 = System.currentTimeMillis();
                    SearchOrderDTO searchOrderDTO = searchManager.searchOrder(searchOrderQuery);
                    logger.info("search spend time:{}", System.currentTimeMillis() - l1);
                    List<BaseIndexOrder> baseIndexOrderList = searchOrderDTO.getOrderList();
                    if (CollectionUtils.isEmpty(baseIndexOrderList)) {
                        break;
                    } else {
                        Date keyDate = new Date(1594137848000L);
                        for (BaseIndexOrder baseIndexOrder : baseIndexOrderList) {
                            if (!StringUtils.isEmpty(baseIndexOrder.getFeatures()) && baseIndexOrder.getUpdatedAt().compareTo(keyDate) < 0) {
                                executorService.submit(() -> {
                                    if (searchManager.updateRy(baseIndexOrder.getOrderId())) {
                                        logger.info("updateSuccess orderNo:{}", baseIndexOrder.getOrderNo());
                                    } else {
                                        logger.info("updateFailed orderNo:{}", baseIndexOrder.getOrderNo());
                                    }
                                });
                            } else {
                                logger.info("orderNo:{} skip", baseIndexOrder.getOrderNo());
                            }
                        }
                    }
                    if (baseIndexOrderList.size() < 200) {
                        break;
                    }
                    copyStartId = baseIndexOrderList.get(baseIndexOrderList.size() - 1).getOrderId();
                }
                start = orderAtEnd;
            }
            logger.info("task stop in Time:{}", start);*/
            result.setStatus(true);
        } catch (Throwable throwable) {
            logger.error("AdminOrderImpl[clearEs] failed, request:{}, cause by:{}",
                    startTime, Throwables.getStackTraceAsString(throwable));
            result.setException(ExceptionConstants.SYSTEM_ERROR);
        }
        return result;
    }

    @Value("${new.sharding.db.size}")
    private Integer dbSize;

    @Value("${new.sharding.tb.size}")
    private Integer tbSize;

    private static final Integer PAGE_SIZE = 1000;


    private void orderDiscountManage(Order order) {
        List<OrderDiscount> discountList = orderDiscountDao.selectByOrderNo(order.getOrderNo(), order.getUserId());
        if (!CollectionUtils.isEmpty(discountList)) {
            order.setDiscountInfo(JSON.toJSONString(discountList));
        }
    }

    @Override
    public void afterPropertiesSet() {
        workQueue = new ArrayBlockingQueue(10240);

        executorService = new ThreadPoolExecutor(4,
                4,
                1,
                TimeUnit.MINUTES,
                workQueue,
                new NamedThreadFactory("dataManage"),
                new ThreadPoolExecutor.CallerRunsPolicy());
    }

    public static void main(String[] args) {
        Map<String, Object> map = new ConcurrentHashMap<>(4);
        map.put("2",1);
        map.put("43",1);
        map.put("121",1);
        map.put("5",1);
        String[]a = new String[4];
        a[0] = "1";
        System.out.println(a.length);
    }
}












