package com.younike.system.service.impl;

import java.math.BigDecimal;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.time.LocalTime;
import java.util.List;
import java.time.LocalDateTime;

import com.alibaba.fastjson.JSON;
import com.younike.common.core.domain.AjaxResult;
import com.younike.common.utils.bean.BeanUtils;
import com.younike.system.domain.Order;
import com.younike.system.domain.OrderStat;
import com.younike.system.domain.vo.DateSectionVO;
import com.younike.system.domain.ServerTimeSection;
import com.younike.system.domain.vo.ServerTimeVo;

import com.younike.common.utils.StringUtils;
import com.younike.system.domain.vo.ServerTimeVo;
import com.younike.system.domain.vo.TimeSectionVO;
import com.younike.system.mapper.OrderGoodsMapper;
import com.younike.system.mapper.OrderMapper;
import com.younike.system.mapper.ServerTimeSectionMapper;
import com.younike.hlpay.dto.OrderParam;
import com.younike.system.param.PaymentParam;
import io.reactivex.rxjava3.core.Single;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import com.younike.system.mapper.ServerTimeMapper;
import com.younike.system.domain.ServerTime;
import com.younike.system.service.IServerTimeService;
import org.springframework.web.client.RestTemplate;

/**
 * 服务人员服务时间Service业务层处理
 *
 * @author elev
 * @date 2022-01-10
 */
@Service
@Log4j2
public class ServerTimeServiceImpl implements IServerTimeService {
    public static final String WEEK_SPLIT = ",";
    @Autowired
    private ServerTimeMapper serverTimeMapper;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private ServerTimeSectionMapper serverTimeSectionMapper;

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

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

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

    /**
     * 修改服务人员服务时间
     *
     * @param serverTime 服务人员服务时间
     * @return 结果
     */
    @Override
    public int updateServerTime(ServerTime 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);
    }

    /**
     * 根据服务人员id查询服务人员工作时间数据
     * @param serverId
     * @return
     */
    @Override
    public ServerTimeVo getServerTime(Long serverId) {

        return serverTimeMapper.getServerTime(serverId);
    }

    /**
     * 根据服务人员id查询服务人员已经被预约的时间
     * @param serverId
     * @return
     */
    @Override
    public List<Order> getServerOrderTime(Long serverId) {
        return serverTimeMapper.getServerOrderTime(serverId);
    }

    /**
     * 查询预约的时间服务人员是否下班
     * @param param
     * @return
     */
    @Override
    public AjaxResult getServerWork(OrderParam param) {

        BigDecimal multiply = new BigDecimal(param.getGoodsCounts()).multiply(param.getSingleTime());
        param.setAppointmentEndTime(param.getAppointmentStartTime().plusHours(multiply.longValue()));
        //创建订单对象
        Order order = new Order();
        BeanUtils.copyProperties(param, order);
        // 校验订单时间是否以及被预约
        List<Order> orders = orderMapper.getOrderList(param);
        if(orders.size()>0){
           return AjaxResult.success("预约失败，超出可预约时间范围",false);
        }
        //星期几
        //验证预约结束世界是否超出服务人员工作时间
        //星期几
        int week = param.getAppointmentEndTime().getDayOfWeek().getValue();
        //时间：时分秒
        LocalTime localTime = param.getAppointmentEndTime().toLocalTime();
        ServerTimeSection serverTimeSection = new ServerTimeSection();
        serverTimeSection.setSectionId(param.getServerId());
        serverTimeSection.setWeeks(String.valueOf(week));
        //查询工作人员工作时间
        ServerTimeSection section =serverTimeSectionMapper.selectSectionWeek(serverTimeSection);

        if(ObjectUtils.isEmpty(section)){
            throw new ArithmeticException("预约失败,超出可预约时间范围");
        }
        if(localTime.isAfter(section.getHoursEnd())){
            throw new ArithmeticException("预约失败,超出可预约时间范围");
        }

        return AjaxResult.success("可预约",true);
    }




    @Override
    public ServerTimeVo getServerTimeInfo(ServerTime serverTime) {
        ServerTimeVo serverTimeInfo = serverTimeMapper.getServerTimeInfo(serverTime);
        serverTimeInfo.getSectionList().forEach(vo -> {
            vo.setWeekNames(this.conversion(vo.getWeeks()));
        });
        return serverTimeInfo;
    }

    /**
     * 把 0,1,2,3,4,5,6 转成对应的 周日周一周二周三周四周五周六
     * @param weeks
     * @return
     */
    private String conversion(String weeks) {
        StringBuffer weekNames = new StringBuffer();

        if (StringUtils.isNotNull(weeks)) {
            if ("0,1,2,3,4,5,6".equals(weeks)) {
                return "每天";
            }

            String[] weekArray = weeks.split(",");
            for (String week : weekArray) {
                switch (week) {
                    case "0":
                        weekNames.append("周日 ");
                        break;
                    case "1":
                        weekNames.append("周一 ");
                        break;
                    case "2":
                        weekNames.append("周二 ");
                        break;
                    case "3":
                        weekNames.append("周三 ");
                        break;
                    case "4":
                        weekNames.append("周四 ");
                        break;
                    case "5":
                        weekNames.append("周五 ");
                        break;
                    case "6":
                        weekNames.append("周六 ");
                        break;
                }
            }
        }
        return new String(weekNames);
    }

    /**
     * @param serverId 服务人员ID
     * @return 服务人员服务时间选择列表
     */
    @Override
    public List<DateSectionVO> getServerTimeSections(Long serverId) {
        List<DateSectionVO> result = new ArrayList<>();
        Map<Integer, DateSectionVO> map = new HashMap<>();
        // 查询服务人员的时间安排
        ServerTime serverTime = new ServerTime();
        serverTime.setServerId(serverId);
        ServerTimeVo serverTimeInfo = serverTimeMapper.getServerTimeInfo(serverTime);
        serverTime = serverTimeMapper.selectServerTimeByServerId(serverId);
        if (serverTimeInfo == null || serverTimeInfo.getSectionList() == null || serverTimeInfo.getSectionList().size() == 0) {
            // 未安排服务时间
            return null;
        }
        // 星期拆分(weeks)
        serverTimeInfo.getSectionList().forEach(vo -> {

            if (vo.getWeeks().contains(WEEK_SPLIT)) {
                // 存在多个工作日相同时间安排
                for (String week : vo.getWeeks().split(WEEK_SPLIT)) {
                    DateSectionVO dateSectionVO = new DateSectionVO();
                    dateSectionVO.setWeek(Integer.parseInt(week));
                    List<TimeSectionVO> timeSectionList = buildTimeSectionVOList(vo.getHoursFrom(), vo.getHoursEnd());
                    dateSectionVO.setTimeSectionList(timeSectionList);
                    map.put(dateSectionVO.getWeek(), dateSectionVO);
                }
            } else {
                // 单个工作日，直接添加
                DateSectionVO dateSectionVO = new DateSectionVO();
                dateSectionVO.setWeek(Integer.parseInt(vo.getWeeks()));
                List<TimeSectionVO> timeSectionList = buildTimeSectionVOList(vo.getHoursFrom(), vo.getHoursEnd());
                dateSectionVO.setTimeSectionList(timeSectionList);
                map.put(dateSectionVO.getWeek(), dateSectionVO);
            }
        });

        // 查询服务人员未来预约订单
        List<Order> orders = orderMapper.listOrderedOrderByServerId(serverId);
        Map<Integer, List<Order>> ordered = orders.stream().collect(Collectors.groupingBy(order -> {
            int value = order.getAppointmentStartTime().getDayOfWeek().getValue();
            if (value == 7) {
                // 周日
                return 0;
            }else{
                return value;
            }
        }));

        // 遍历生成未来七天的数据
        // 星期几（sun start, 1 -> 7）
        int week = Calendar.getInstance().get(Calendar.DAY_OF_WEEK);
        if (week == 7) {
            // 今天是周六，明天是周天（0）
            week = 0;
        }
        LocalDate nextDate = LocalDate.now().plusDays(1L);
        for (int i = 0; i < 7; i++) {
            DateSectionVO dateSectionVO = map.get(week);
            if (week == 2) {
                log.info("2");
            }
            if (dateSectionVO == null) {
                // 没有服务排班
                dateSectionVO = new DateSectionVO();
                dateSectionVO.setWeek(week);
            } else {
                // 查询是否已经有服务计划
                List<Order> orderedList = ordered.get(week);
                if (orderedList != null && orderedList.size() > 0) {
                    DateSectionVO finalDateSectionVO = dateSectionVO;
                    ServerTime finalServerTime = serverTime;
                    orderedList.forEach(order -> {
                        LocalTime startTime = order.getAppointmentStartTime().toLocalTime();
                        // 结束时间添加服务间隔
                        LocalTime endTime = order.getAppointmentEndTime().plusMinutes(finalServerTime.getServerGrap().multiply(BigDecimal.valueOf(60)).longValue()).toLocalTime();

                        List<TimeSectionVO> timeSectionList = finalDateSectionVO.getTimeSectionList();
                        boolean booked = false;
                        for (TimeSectionVO timeSectionVO : timeSectionList) {
                            if (timeSectionVO.getStartTime().equals(startTime)) {
                                booked = true;
                            }
                            timeSectionVO.setBooked(booked);
                            if (timeSectionVO.getEndTime().equals(endTime)) {
                                booked = false;
                            }
                        }
                    });
                }
            }
            dateSectionVO.setDate(nextDate.toString());
            log.info(nextDate.toString());
            nextDate = nextDate.plusDays(1L);
            result.add(dateSectionVO);
            week= week + 1;
            if (week > 6) {
                week = 0;
            }
        }
        return result;
    }

    /**
     * @param hoursFrom 开始时间
     * @param hoursEnd 结束时间
     * @return 服务时间集合
     */
    private List<TimeSectionVO> buildTimeSectionVOList(LocalTime hoursFrom, LocalTime hoursEnd){
        List<TimeSectionVO> list = new ArrayList<>();
        Duration duration = java.time.Duration.between(hoursFrom, hoursEnd);
        long minutes = duration.toMinutes();
        LocalTime startTime = hoursFrom;
        for (long i = 0; i < (minutes / 30); i++) {
            TimeSectionVO vo = new TimeSectionVO();
            vo.setStartTime(startTime);
            startTime = startTime.plusMinutes(30);
            vo.setEndTime(startTime);
            list.add(vo);
        }
        return list;
    }

    public static void main(String[] args) {
        System.out.println( Calendar.getInstance().get(Calendar.DAY_OF_WEEK));
    }


}
