package com.younike.system.service.impl;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.younike.common.exception.ServiceException;
import com.younike.common.utils.SecurityUtils;
import com.younike.system.domain.Order;
import com.younike.system.domain.ServerTimeBook;
import com.younike.system.domain.ServerTimeSection;
import com.younike.system.domain.vo.ServerTimeSectionVo;
import com.younike.system.domain.vo.ServerTimesVO;
import com.younike.system.enums.BookStatusEnum;
import com.younike.system.mapper.MerchantServerTimeMapper;
import com.younike.system.mapper.OrderMapper;
import com.younike.system.mapper.ServerTimeBookMapper;
import com.younike.system.mapper.ServerTimeSectionMapper;
import com.younike.system.service.IMerchantServerTimeService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.younike.system.enums.BookStatusEnum.*;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;

/**
 * 服务人员服务时间Service业务层处理
 *
 * @author elev
 * @date 2022-01-07
 */
@Service
public class MerchantServerTimeServiceImpl implements IMerchantServerTimeService {

    private static final Logger log = LoggerFactory.getLogger(MerchantServerTimeServiceImpl.class);

    @Autowired
    private MerchantServerTimeMapper serverTimeMapper;
    @Autowired
    private ServerTimeSectionMapper serverTimeSectionMapper;
    @Autowired
    private ServerTimeBookMapper serverTimeBookMapper;
    @Autowired
    private OrderMapper orderMapper;

    /**
     * 查询服务人员服务时间
     *
     * @param serverId 服务人员服务时间主键
     * @return 服务人员服务时间
     */
    @Override
    public ServerTimesVO selectServerTimeByServerId(Long serverId) {
        return serverTimeMapper.selectServerTimeByServerId(serverId);
    }

    /**
     * 查询服务人员服务时间列表
     *
     * @param serverTime 服务人员服务时间
     * @return 服务人员服务时间
     */
    @Override
    public List<ServerTimesVO> selectServerTimeList(ServerTimesVO serverTime) {
        return serverTimeMapper.selectServerTimeList(serverTime);
    }

    /**
     * 新增服务人员服务时间
     *
     * @param serverTime 服务人员服务时间
     * @return 结果
     */
    @Override
    public int insertServerTime(ServerTimesVO serverTime) {
//        serverTime.setCreateTime(LocalDateTime.now());
        return serverTimeMapper.insertServerTime(serverTime);
    }

    /**
     * 修改服务人员服务时间
     *
     * @param serverTime 服务人员服务时间
     * @return 结果
     */
    @Override
    public int updateServerTime(ServerTimesVO serverTime) {
//        serverTime.setUpdateTime(LocalDateTime.now());
        return serverTimeMapper.updateServerTime(serverTime);
    }

    /**
     * 批量删除服务人员服务时间
     *
     * @param serverIds 需要删除的服务人员服务时间主键
     * @return 结果
     */
    @Override
    public int deleteServerTimeByServerIds(Long[] serverIds) {
        return serverTimeMapper.deleteServerTimeByServerIds(serverIds);
    }

    /**
     * 删除服务人员服务时间信息
     *
     * @param serverId 服务人员服务时间主键
     * @return 结果
     */
    @Override
    public int deleteServerTimeByServerId(Long serverId)
    {
        return serverTimeMapper.deleteServerTimeByServerId(serverId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateServerTimeNew(ServerTimesVO serverTime) {
        Long serverId = serverTime.getServerId();
        // 1. 保存服务时间
        ServerTimesVO serverTimesVO = serverTimeMapper.selectServerTimeByServerIdNew(serverId);
        int successNum = 0;
        if(ObjectUtils.isEmpty(serverTimesVO)){
            serverTime.setDelFlag("0");
            serverTime.setCreateBy(SecurityUtils.getUserId().toString());
            serverTime.setCreateTime(LocalDateTime.now());
            serverTime.setUpdateBy(SecurityUtils.getUserId().toString());
            serverTime.setUpdateTime(LocalDateTime.now());
            successNum = serverTimeMapper.insertServerTimeCustom(serverTime);
        }else {
            serverTime.setUpdateBy(SecurityUtils.getUserId().toString());
            serverTime.setUpdateTime(LocalDateTime.now());
            successNum = serverTimeMapper.updateServerTime(serverTime);
        }
        if(successNum>0){
            //删除
            serverTimeSectionMapper.deleteServerTimeSectionByServerId(serverTime);
            //插入
            for(ServerTimeSectionVo addInfo:serverTime.getSectionList()){
                addInfo.setSectionId(null);
                addInfo.setIsEnable("1");
                addInfo.setServerId(serverId +"");
                addInfo.setDelFlag("0");
                addInfo.setCreateBy(SecurityUtils.getUserId().toString());
                addInfo.setCreateTime(LocalDateTime.now());
                addInfo.setUpdateBy(SecurityUtils.getUserId().toString());
                addInfo.setUpdateTime(LocalDateTime.now());
                serverTimeSectionMapper.insertServerTimeSectionVo(addInfo);
            }
        }

        generateBookTimes(serverId, SecurityUtils.getUserId());

        return 1;
    }

    /**
     * 重新生成服务人员的可预约时间
     * @param serverId
     * @param user
     */
    @Override
    public void generateBookTimes(Long serverId, Long user) {
        log.info("开始重新生成服务人员预约时间：" + serverId);
        ServerTimeSection param = new ServerTimeSection();
        param.setServerId(serverId.toString());
        param.setIsEnable("1");
        ServerTimesVO serverTimesVO = serverTimeMapper.selectServerTimeByServerIdNew(serverId);
        List<ServerTimeSection> serverTimeSectionList = serverTimeSectionMapper.selectServerTimeSectionList(param);
        if (Objects.isNull(serverTimesVO) || CollectionUtils.isEmpty(serverTimeSectionList)){
            log.info("服务人员未配置服务时间");
            serverTimeBookMapper.removeBookedList(serverId);
            return;
        }
        // 重新生成预约记录(从明天开始的一周)
        // 1 获取服务人员当前服务时间配置
        Map<Integer, List<ServerTimeSection>> serverTimeMap = Maps.newHashMap();
        serverTimeSectionList.stream().forEach(serverTimeSection -> {
            Arrays.stream(serverTimeSection.getWeeks().split(",")).map(Integer::valueOf).forEach(week -> {
                List<ServerTimeSection> timeList = serverTimeMap.get(week);
                if (CollectionUtils.isNotEmpty(timeList)){
                    timeList.add(serverTimeSection);
                } else {
                    serverTimeMap.put(week, Lists.newArrayList(serverTimeSection));
                }
            });
        });

        // 2 获取该服务人员当前预约订单
        List<Order> bookedList = orderMapper.selectServerBookedOrder(serverId);
        Map<LocalDate, List<Order>> orderMap = bookedList.stream().collect(groupingBy(order -> order.getAppointmentStartTime().toLocalDate()));
        log.info("获取到的预约订单：" + bookedList.stream().map(Order::getOrderId).collect(toList()));

        // 3 生成从明天开始一周的服务时间预约数据
        List<ServerTimeBook> bookList = Lists.newArrayList();
        LocalDateTime today = LocalDate.now().atStartOfDay();
        for (long i=1; i<=7; i++){
            LocalDateTime day = today.plusDays(i);
            // 3.1 获取当天的可服务时间段
            Integer dayOfWeek = DayOfWeek.SUNDAY.equals(day.getDayOfWeek()) ? 0: day.getDayOfWeek().getValue();
            List<ServerTimeSection> timeList = serverTimeMap.get(dayOfWeek);
            if (CollectionUtils.isEmpty(timeList)) continue;

            // 3.2 获取当天已预约时间段
            List<Order> orderList = orderMap.get(day.toLocalDate());

            // 3.3 生成预约时间数据
            timeList.stream().forEach(serverTimeSection -> {
                LocalTime startTime = serverTimeSection.getHoursFrom();
                LocalTime endTime = serverTimeSection.getHoursEnd();
                while(startTime.isBefore(endTime)) {
                    ServerTimeBook serverTimeBook = new ServerTimeBook();
                    serverTimeBook.setServerId(serverId);
                    serverTimeBook.setServerDate(day);
                    serverTimeBook.setWeek(dayOfWeek);
                    serverTimeBook.setStartTime(startTime);
                    LocalTime next = startTime.plusMinutes(30L);
                    serverTimeBook.setEndTime(next);
                    serverTimeBook.setCreateBy(user.toString());
                    serverTimeBook.setCreateTime(LocalDateTime.now());
                    serverTimeBook.setBooked(BOOKABLE.getValue());
                    if (CollectionUtils.isNotEmpty(orderList)){
                        for(Order order: orderList){
                            LocalTime orderStart = order.getAppointmentStartTime().toLocalTime();
                            LocalTime orderEnd = order.getAppointmentEndTime().toLocalTime();
                            LocalTime grapEnd = orderEnd.plusMinutes((long) (60 * serverTimesVO.getServerGrap().doubleValue()));
                            if ((startTime.compareTo(orderStart) >= 0) && (next.compareTo(orderEnd) <= 0)){
                                serverTimeBook.setBooked(BOOKED.getValue());
                            }
                            if ((startTime.compareTo(orderEnd) >= 0) && (next.compareTo(grapEnd) <= 0)){
                                serverTimeBook.setBooked(NOT_BOOKABLE.getValue());
                            }
                        }
                    }
                    bookList.add(serverTimeBook);
                    startTime = next;
                }
            });
        }
        serverTimeBookMapper.removeBookedList(serverId);
        serverTimeBookMapper.insertBatch(bookList);
    }
}
