package com.happy.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.happy.Model.Holiday;
import com.happy.Model.House;
import com.happy.Model.HouseNumber;
import com.happy.Model.HouseNumberStatus;
import com.happy.Until.DateUtil;
import com.happy.Until.Func;
import com.happy.Until.TimeExchange;
import com.happy.dao.HouseNumberDao;
import com.happy.dao.HouseNumberStatusDao;
import com.happy.dao.HousePriceDao;
import com.happy.dto.HouseNumberDto;
import com.happy.dto.HouseNumberStatusDto;
import com.happy.dto.HousePriceDto;
import com.happy.service.HouseNumberStatusService;
import com.happy.service.HousePriceService;
import lombok.SneakyThrows;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.beans.PropertyDescriptor;
import java.text.ParseException;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@Service("HouseNumberStatusService")
public class HouseNumberStatusImplService implements HouseNumberStatusService {

    @Resource(name = "HouseNumberStatusDao")
    public HouseNumberStatusDao houseNumberStatusDao;
    @Resource(name = "housePriceService")
    private HousePriceService housePriceService;
    @Resource(name = "HouseNumberDao")
    public HouseNumberDao houseNumberDao;
    @Resource(name = "housePriceDao")
    public HousePriceDao housePriceDao;


    @Override
    public int deleteHolidayByYear(String year) {
        return houseNumberStatusDao.deleteHolidayByYear(year);
    }

    @Override
    public int saveHolidayBatch(List<Holiday> list) {
        return houseNumberStatusDao.saveHolidayBatch(list);
    }

    @Override
    public List<Holiday> queryHolidays(String year, String startDate, String endDates) {

        List<Holiday> list = houseNumberStatusDao.queryHolidays(year, startDate, endDates);
        return list;
    }

    @Override
    public int saveBatch(List<HouseNumberStatus> list) {
        return houseNumberStatusDao.saveBatch(list);
    }



    @Override
    public int updateHouseNumberStatus(String bookId) {
        return houseNumberStatusDao.updateHouseNumberStatus(bookId);
    }

    @Override
    public List<HouseNumberStatus> getList(String sqlx) {
        return houseNumberStatusDao.getList(sqlx);
    }

    @Override
    public JSONObject queryData(HouseNumberStatusDto houseNumberStatusDto,Integer pageNumber, Integer pageSize) {
        String managerId = houseNumberStatusDto.getManagerId();
        Integer showType = houseNumberStatusDto.getShowType();
        if (StringUtils.isBlank(managerId) || showType == null) return null;
        JSONObject housePage = housePriceService.queryPageHouseListByManagerId(houseNumberStatusDto.getManagerId(),pageNumber,pageSize);
        List<House> houseList = JSON.parseArray(housePage.getJSONArray("pageList").toJSONString(), House.class);
        if (houseList == null || houseList.isEmpty()) return null;
        HouseNumberDto houseNumberDto = new HouseNumberDto();
        houseNumberDto.setHouseIdList(houseList.stream().map(House::getId).collect(Collectors.toList()));
        List<HouseNumberDto> houseNumberList = houseNumberDao.queryListOne(houseNumberDto);
        if (houseNumberList == null || houseNumberList.isEmpty()) return null;

        String setDate = houseNumberStatusDto.getSetDate();
        Date startDate = DateUtil.parseDateOnly(setDate);
        Date endDate = DateUtil.addDate(startDate, Calendar.DATE, 28);
        String setDateWithEndDate = String.format("%s,%s", setDate, DateUtil.parseDateToStr(endDate, DateUtil.Time_Formatter_Day));

        //region 房间状态信息
        houseNumberStatusDto.setStatuses(Arrays.asList(2, 5, 6));
        List<String> houseNumberIdList = houseNumberList.stream().map(HouseNumber::getId).collect(Collectors.toList());
        houseNumberStatusDto.setHouseNumberIds(houseNumberIdList);
        List<HouseNumberStatusDto> houseNumberStatusDtoList;
        if (showType == 1) {
            houseNumberStatusDto.setSetDate(setDateWithEndDate);
            // 周日内的房间状态信息
            houseNumberStatusDtoList = houseNumberStatusDao.queryList(houseNumberStatusDto);
        } else if (showType == 2) {
            // 当日的房间状态信息
            houseNumberStatusDtoList = houseNumberStatusDao.queryList(houseNumberStatusDto);
        } else {
            houseNumberStatusDtoList = Collections.emptyList();
        }
        //endregion

        if (!houseNumberStatusDtoList.isEmpty()) {
            //region 预定/入住的订单信息
            Map<String, HouseNumberStatusDto> orderInfoMap;
            List<String> bookingId = houseNumberStatusDtoList.stream()
                    .filter(item -> item.getStatus() == 5 || item.getStatus() == 6)
                    .map(HouseNumberStatusDto::getBookingId).collect(Collectors.toList());
            if (bookingId.isEmpty()) {
                orderInfoMap = Collections.emptyMap();
            } else {
                orderInfoMap = houseNumberStatusDao.queryOrderSomeColumnListByIds(bookingId)
                        .stream().collect(Collectors.toMap(HouseNumberStatusDto::getBookingId, item -> item, (bookingIdOne, bookingIdTow) -> bookingIdOne));
            }
            //endregion

            houseNumberList.forEach(houseNumber -> {
                List<HouseNumberStatusDto> houseNumberStatuses = new ArrayList<>();
                for (HouseNumberStatusDto numberStatusDto : houseNumberStatusDtoList) {
                    // 填充预定/入住的一些订单信息
                    if (numberStatusDto.getStatus() == 5 || numberStatusDto.getStatus() == 6) {
                        HouseNumberStatusDto score = orderInfoMap.getOrDefault(numberStatusDto.getBookingId(), new HouseNumberStatusDto());
                        BeanUtils.copyProperties(score, numberStatusDto, getNullPropertyNames(score));
                    }
                    // 填充房间状态信息
                    if (Objects.equals(houseNumber.getId(), numberStatusDto.getNumberId())) {
                        houseNumberStatuses.add(numberStatusDto);
                        houseNumber.setHouseNumberStatuses(houseNumberStatuses);
                    }
                }
            });
        }
        if (houseNumberStatusDto.getShowType() == 1) {
            List<String> dateListBetween = DateUtil.getDateStrListBetween(startDate, endDate);

            //region 周期内的改价记录
            HousePriceDto housePriceDto = new HousePriceDto();
            List<String> houseIdList = houseList.stream().map(House::getId).collect(Collectors.toList());
            housePriceDto.setHouseIdList(houseIdList);
            housePriceDto.setSetDate(setDateWithEndDate);
            List<HousePriceDto> housePriceDtoList = housePriceDao.queryListTwo(housePriceDto);
            //endregion
            List<JSONObject> datas = new ArrayList<>();
            houseList.forEach(house -> houseNumberList.forEach(houseNumber -> {
                if (houseNumber.getHouseId().equals(house.getId())) {
                    JSONObject houseJsonObject = new JSONObject(new LinkedHashMap<>());
                    houseJsonObject.put("id", house.getId());
                    houseJsonObject.put("houseName", house.gethName());
                    String numberName = houseNumber.getNumberName();
                    houseJsonObject.put("numberName", numberName);
                    houseJsonObject.put("numberStatus", houseNumber.getHouseStatus());
                    houseJsonObject.put("numberId", houseNumber.getId());
                    dateListBetween.forEach(date -> {
                        JSONObject dateJsonObject = new JSONObject();
                        dateJsonObject.put("numberId", houseNumber.getId());
                        dateJsonObject.put("houseName", house.gethName());
                        dateJsonObject.put("numberName", numberName);
                        dateJsonObject.put("housePrice", getPrice(DateUtil.parseDateOnly(date), house, housePriceDtoList));
                        List<HouseNumberStatusDto> houseNumberStatuses = houseNumber.getHouseNumberStatuses();
                        if (houseNumberStatuses != null && !houseNumberStatuses.isEmpty()) {
                            houseNumberStatuses.forEach(houseNumberStatus -> {
                                if (date.equals(houseNumberStatus.getSetDate())) {
                                    dateJsonObject.put("closeType", houseNumberStatus.getCloseType());
                                    dateJsonObject.put("remark", houseNumberStatus.getRemark());
                                    dateJsonObject.put("setDate", houseNumberStatus.getSetDate());
                                    dateJsonObject.put("status", houseNumberStatus.getStatus());
                                    if (houseNumberStatus.getStatus() == 5 || houseNumberStatus.getStatus() == 6) {
                                        dateJsonObject.put("orderNum", houseNumberStatus.getOrderNum());
                                        dateJsonObject.put("orderUserName", houseNumberStatus.getOrderUserName());
                                        dateJsonObject.put("orderUserPhone", houseNumberStatus.getOrderUserPhone());
                                        dateJsonObject.put("orderPayAccount", houseNumberStatus.getOrderPayAccount());
                                        dateJsonObject.put("orderStartTime", houseNumberStatus.getOrderStartTime());
                                        dateJsonObject.put("orderEndTime", houseNumberStatus.getOrderEndTime());
                                    }
                                }
                            });
                        }
                        houseJsonObject.put(date, dateJsonObject);
                    });
                    datas.add(houseJsonObject);
                }
            }));

            List<Holiday> holidays = houseNumberStatusDao.queryHolidays( String.valueOf(LocalDate.now().getYear()),TimeExchange.DateToString(startDate,"yyyy-MM-dd"),TimeExchange.DateToString(endDate,"yyyy-MM-dd"));

            ArrayList<JSONObject> dataTimes = new ArrayList<>();
            try{

                dateListBetween.forEach(date -> {
                    System.out.println("测试服务器进来了");
                    JSONObject dataTime = new JSONObject();
                    dataTime.put("dateStr", date);
                    dataTime.put("roomSum", getSum(date, houseNumberList));
                    //2023-09-20 A-jax 添加 星期 节假日 是否休息
                    try {
                        dataTime.put("weekStr", TimeExchange.getWeek(date));//星期
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    System.out.println("测试服务器进来了1");
                    String holidayStr = null;
                    if(holidays != null && holidays.size() > 0){
                        Optional<Holiday> holiday = holidays.stream().filter(e -> e.getDate().equals(date)).findFirst();
                        holidayStr = null;
                        if(holiday != null && holiday.isPresent()){
                            Holiday data = holiday.get();
                            holidayStr = data.getIsRest().intValue() == 1 ? data.getName() : "班";
                        }
                    }

                    dataTime.put("holiday",holidayStr);//节假日
                    dataTimes.add(dataTime);
                });
            }catch (Exception e){
                System.out.println("错误信息："+e.getMessage());
            }

            housePage.put("dateTimes", dataTimes);
            housePage.put("pageList", datas);
            return housePage;
        }
        if (houseNumberStatusDto.getShowType() == 2) {
            housePage.put("pageList", buildResultOne(houseList, houseNumberList));
            return housePage;
        }
        return null;
    }

    @Override
    public List<?> queryListWithHouse(HouseNumberStatusDto houseNumberStatusDto) {
        String managerId = houseNumberStatusDto.getManagerId();
        if (StringUtils.isBlank(managerId)) return Collections.emptyList();
        List<House> houseList = housePriceService.queryHouseListByManagerId(houseNumberStatusDto.getManagerId());
        if (houseList == null || houseList.isEmpty()) return houseList;
        HouseNumberDto houseNumberDto = new HouseNumberDto();
        houseNumberDto.setHouseIdList(houseList.stream().map(House::getId).collect(Collectors.toList()));
        houseNumberDto.setHouseStatus(houseNumberStatusDto.getStatus());
        List<HouseNumberDto> houseNumberList = houseNumberDao.queryListOne(houseNumberDto);
        if (houseNumberList == null || houseNumberList.isEmpty()) return houseList;
        return buildResultOne(houseList, houseNumberList);
    }

    @SneakyThrows
    @Override
    public void modifyStatusBatch(HouseNumberStatusDto houseNumberStatusDto) {
        Integer status = houseNumberStatusDto.getStatus();
        String createId = houseNumberStatusDto.getCreateId();
        Date dataTime = DateUtil.formateDate(DateUtil.getCurrentDate(), DateUtil.Time_Formatter_Second);
        if (status == 2) {
            // 关房
            String[] setDateStr = houseNumberStatusDto.getSetDate().split(",");
            List<String> dateStrListBetween = DateUtil.getDateStrListBetween(DateUtil.parseDateOnly(setDateStr[0]), DateUtil.parseDateOnly(setDateStr[1]));
            List<String> houseNumberIds = houseNumberStatusDto.getHouseNumberIds();
            List<HouseNumberStatus> houseNumberStatusList = new ArrayList<>();
            houseNumberIds.forEach(houseNumberId -> {
                HouseNumberStatus houseNumberStatus = new HouseNumberStatus();
                houseNumberStatus.setNumberId(houseNumberId);
                houseNumberStatus.setStatus(status);
                houseNumberStatus.setCreateId(createId);
                houseNumberStatus.setCreateDate(dataTime);
                dateStrListBetween.forEach(dateStr -> {
                    HouseNumberStatus houseNumberStatusNew = new HouseNumberStatus();
                    BeanUtils.copyProperties(houseNumberStatus, houseNumberStatusNew);
                    houseNumberStatusNew.setId(Func.newGuid());
                    houseNumberStatusNew.setCloseType(houseNumberStatusDto.getCloseType());
                    houseNumberStatusNew.setSetDate(dateStr);
                    houseNumberStatusNew.setRemark(houseNumberStatusDto.getRemark());
                    houseNumberStatusList.add(houseNumberStatusNew);
                });
            });
            houseNumberStatusDao.saveBatch(houseNumberStatusList);
        } else if (status == 0) {
            // 开房
            houseNumberStatusDto.setModifyDate(dataTime);
            houseNumberStatusDao.updateStatus(houseNumberStatusDto);
        }
    }

    @SneakyThrows
    @Override
    public void modifyStatus(HouseNumberStatusDto houseNumberStatusDto) {
        Integer status = houseNumberStatusDto.getStatus();
        String createId = houseNumberStatusDto.getCreateId();
        Date dataTime = DateUtil.formateDate(DateUtil.getCurrentDate(), DateUtil.Time_Formatter_Second);
        if (status == 2) {
            // 关房
            HouseNumberStatus houseNumberStatus = new HouseNumberStatus();
            BeanUtils.copyProperties(houseNumberStatusDto, houseNumberStatus);
            houseNumberStatus.setId(Func.newGuid());
            houseNumberStatus.setCreateDate(dataTime);
            houseNumberStatus.setCreateId(createId);
            houseNumberStatusDao.saveBatch(Collections.singletonList(houseNumberStatus));
        } else if (status == 0) {
            // 开房
            houseNumberStatusDto.setModifyDate(dataTime);
            houseNumberStatusDao.updateStatus(houseNumberStatusDto);
        }
    }

    private List<JSONObject> buildResultOne(List<House> houseList, List<HouseNumberDto> houseNumberList) {
        List<JSONObject> result = new ArrayList<>();
        Map<String, List<HouseNumber>> houseNumberMap = houseNumberList.stream().collect(Collectors.groupingBy(HouseNumber::getHouseId));
        houseList.forEach(house -> {
            JSONObject houseJosoObj = (JSONObject) JSONObject.toJSON(house);
            houseJosoObj.put("houseNumberList", houseNumberMap.getOrDefault(house.getId(), Collections.emptyList()));
            result.add(houseJosoObj);
        });
        return result;
    }

    /**
     * 获取对象null值属性名称,用于BeanUtils.copyProperties忽略字段
     */
    private String[] getNullPropertyNames(Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        PropertyDescriptor[] pds = src.getPropertyDescriptors();
        Set<String> emptyNames = new HashSet<String>();
        for (PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null) {
                emptyNames.add(pd.getName());
            }
        }
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }

    /**
     * 获取房型指定日期的价格
     *
     * @return 原价 or 周日内最新一条改价记录的价格
     */
    private Double getPrice(Date dateIn, House house, List<HousePriceDto> housePriceDtoList) {
        Double price = house.getPrice();
        if (housePriceDtoList == null || housePriceDtoList.isEmpty()) return price;
        for (HousePriceDto priceDto : housePriceDtoList) {
            String[] date = priceDto.getSetDate().split(",");
            Date startDate = DateUtil.parseDateOnly(date[0]);
            Date endDate = DateUtil.parseDateOnly(date[1]);
            assert startDate != null;
            boolean flag = DateUtil.isEffectiveDate(dateIn, startDate, endDate) && house.getId().equals(priceDto.getHouseId());
            if (flag) {
                price = priceDto.getPrice();
                break;
            }
        }
        return price;
    }

    /**
     * 获取当日房型剩余房间号
     *
     * @return 当天剩余房间数量
     */
    private int getSum(String dateIn, List<HouseNumberDto> houseNumberList) {
        int total = houseNumberList.size();
        int used = 0;
        for (HouseNumberDto houseNumber : houseNumberList) {
            List<HouseNumberStatusDto> houseNumberStatuses = houseNumber.getHouseNumberStatuses();
            if (houseNumberStatuses != null && !houseNumberStatuses.isEmpty()) {
                boolean flag = houseNumberStatuses.stream().anyMatch(item -> dateIn.equals(item.getSetDate()));
                if (flag) {
                    used++;
                }
            }
        }
        return total - used;
    }
}
