package com.xxfc.platform.vehicle.biz;

import com.github.wxiaoqi.security.common.biz.BaseBiz;
import com.github.wxiaoqi.security.common.exception.BaseException;
import com.google.common.collect.Lists;
import com.xxfc.platform.vehicle.entity.Festival;
import com.xxfc.platform.vehicle.entity.VehicleModelHolidayPrice;
import com.xxfc.platform.vehicle.mapper.VehicleModelHolidayPriceMapper;
import com.xxfc.platform.vehicle.pojo.dto.VehicleModelHolidayPriceDTO;
import com.xxfc.platform.vehicle.pojo.dto.VehicleModelHolidayPriceFindDTO;
import com.xxfc.platform.vehicle.pojo.dto.VehicleModelHolidayPriceSaveDTO;
import com.xxfc.platform.vehicle.pojo.vo.VehicleModelHolidayPriceVo;
import com.xxfc.platform.vehicle.util.DateUtils;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author libin
 * @version 1.0
 * @description
 * @data 2019/10/14 17:32
 */
@Transactional(rollbackFor = Exception.class)
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class VehicleModelHolidayPriceBiz extends BaseBiz<VehicleModelHolidayPriceMapper, VehicleModelHolidayPrice> {

    private final FestivalBiz festivalBiz;

    /**
     * 保存
     *
     * @param vehicleModelHolidayPriceSaveDTO
     * @param userId
     */
    public void addVehicleModelHolidayPrice(VehicleModelHolidayPriceSaveDTO vehicleModelHolidayPriceSaveDTO, Integer userId) {
        List<VehicleModelHolidayPrice> vehicleModelHolidayPriceList = new ArrayList<>();
        VehicleModelHolidayPrice vehicleModelHolidayPrice;

        LocalDate startLocaldate = DateUtils.dateToLocalDate(vehicleModelHolidayPriceSaveDTO.getStartDate());
        LocalDate endLocaldate = DateUtils.dateToLocalDate(vehicleModelHolidayPriceSaveDTO.getEndDate());
        while (startLocaldate.isBefore(endLocaldate) || startLocaldate.isEqual(endLocaldate)){
            vehicleModelHolidayPrice = new VehicleModelHolidayPrice();
            BeanUtils.copyProperties(vehicleModelHolidayPriceSaveDTO, vehicleModelHolidayPrice);
            Date date = DateUtils.localDateToDate(startLocaldate);
            vehicleModelHolidayPrice.setFestivalDay(date);
            vehicleModelHolidayPriceList.add(vehicleModelHolidayPrice);
            startLocaldate = startLocaldate.plusDays(1);
        }
        //编辑
        if (Objects.nonNull(vehicleModelHolidayPriceSaveDTO.getId())) {
            Example example = new Example(VehicleModelHolidayPrice.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("festivalId", vehicleModelHolidayPriceSaveDTO.getId());
            for (VehicleModelHolidayPrice modelHolidayPrice : vehicleModelHolidayPriceList) {
                modelHolidayPrice.setUpdUserId(userId);
                modelHolidayPrice.setUpdTime(new Date());
                mapper.updateByExampleSelective(modelHolidayPrice, example);
            }
            Festival festival = new Festival();
            festival.setName(vehicleModelHolidayPriceSaveDTO.getFestival());
            festival.setId(vehicleModelHolidayPriceSaveDTO.getId());
            festivalBiz.add(festival);
        } else {
            Festival festival = new Festival();
            festival.setName(vehicleModelHolidayPriceSaveDTO.getFestival());
            festivalBiz.add(festival);
            for (VehicleModelHolidayPrice modelHolidayPrice : vehicleModelHolidayPriceList) {
                modelHolidayPrice.setCrtTime(new Date());
                modelHolidayPrice.setCrtUserId(userId);
                modelHolidayPrice.setFestivalId(festival.getId());
                mapper.insertSelective(modelHolidayPrice);
            }
        }
    }

    /**
     * @param multiple   倍数
     * @param freeDays   免费天数
     */
    public void updateVehicleModelHolidayPrice(Double multiple, Integer freeDays) {
        VehicleModelHolidayPrice vehicleModelHolidayPrice = new VehicleModelHolidayPrice();
        vehicleModelHolidayPrice.setMultiple(multiple);
        vehicleModelHolidayPrice.setFreeDays(freeDays);
        Example example = new Example(VehicleModelHolidayPrice.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("isDel",0);
        mapper.updateByExampleSelective(vehicleModelHolidayPrice,example);
    }

    /**
     * 按年 月 节假日 等条件查询
     *
     * @param vehicleModelHolidayPriceFindDTO
     * @return
     */
    public List<VehicleModelHolidayPriceVo> listVehicleModelHolidayPrice(VehicleModelHolidayPriceFindDTO vehicleModelHolidayPriceFindDTO) {
        List<VehicleModelHolidayPriceVo> vehicleModelHolidayPriceVos = new ArrayList<>();
        Example example = new Example(VehicleModelHolidayPrice.class);
        Example.Criteria criteria = example.createCriteria();
        Date date = null;
        if (StringUtils.isNotEmpty(vehicleModelHolidayPriceFindDTO.getDate()) && vehicleModelHolidayPriceFindDTO.getDate().trim().length() > 0) {
            date = Date.from(LocalDate.parse(vehicleModelHolidayPriceFindDTO.getDate()).atStartOfDay(ZoneId.systemDefault()).toInstant());
        }
        setCondtionDate(date, vehicleModelHolidayPriceFindDTO.getYear(), criteria);
        if (StringUtils.isNotEmpty(vehicleModelHolidayPriceFindDTO.getFestival()) && vehicleModelHolidayPriceFindDTO.getFestival().trim().length() > 0) {
            criteria.andLike("festival", String.format("%%%s%%", vehicleModelHolidayPriceFindDTO.getFestival()));
        }
        criteria.andEqualTo("isDel",0);
        List<VehicleModelHolidayPrice> holidayPrices = mapper.selectByExample(example);
        if (CollectionUtils.isEmpty(holidayPrices)) {
            return vehicleModelHolidayPriceVos;
        }
        List<Integer> festivalIds = holidayPrices.stream().map(VehicleModelHolidayPrice::getFestivalId).collect(Collectors.toList());
        Map<Integer,Festival> festivalMap = festivalBiz.findFestivalsByIds(festivalIds);
        Map<Integer, List<VehicleModelHolidayPrice>> listMap = holidayPrices.stream().collect(Collectors.groupingBy(VehicleModelHolidayPrice::getFestivalId, Collectors.toList()));
        VehicleModelHolidayPriceVo vehicleModelHolidayPriceVo;

        for (Integer festivalId : listMap.keySet()) {
            vehicleModelHolidayPriceVo = new VehicleModelHolidayPriceVo();
            BeanUtils.copyProperties(listMap.get(festivalId).get(0), vehicleModelHolidayPriceVo);
            vehicleModelHolidayPriceVo.setFestival(festivalMap==null?"":festivalMap.get(festivalId).getName());
            Date startDate = listMap.get(festivalId).stream().map(VehicleModelHolidayPrice::getFestivalDay).min(Date::compareTo).get();
            Date endDate = listMap.get(festivalId).stream().map(VehicleModelHolidayPrice::getFestivalDay).max(Date::compareTo).get();
            vehicleModelHolidayPriceVo.setStartDate(startDate);
            vehicleModelHolidayPriceVo.setEndDate(endDate);
            vehicleModelHolidayPriceVo.setId(Long.valueOf(festivalId));
            vehicleModelHolidayPriceVos.add(vehicleModelHolidayPriceVo);
        }
        return vehicleModelHolidayPriceVos;
    }

    /**
     * 根据开始与结束时间查询
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public List<VehicleModelHolidayPriceDTO> findVehicleModelHolidayPriceByMonth(Date startDate, Date endDate) {
        List<VehicleModelHolidayPriceDTO> vehicleModelHolidayPriceDTOS = new ArrayList<>();
        Example example = new Example(VehicleModelHolidayPrice.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andBetween("festivalDay", startDate, endDate);
        criteria.andEqualTo("isDel",0);
        List<VehicleModelHolidayPrice> modelHolidayPrices = mapper.selectByExample(example);
        if (CollectionUtils.isEmpty(modelHolidayPrices)) {
            return vehicleModelHolidayPriceDTOS;
        }
        List<Integer> festivalIds = modelHolidayPrices.stream().map(VehicleModelHolidayPrice::getFestivalId).collect(Collectors.toList());
        Map<Integer,Festival> festivalMap = festivalBiz.findFestivalsByIds(festivalIds);

        Map<Date, List<VehicleModelHolidayPrice>> dateListMap = modelHolidayPrices.stream().collect(Collectors.groupingBy(VehicleModelHolidayPrice::getFestivalDay, Collectors.toList()));
        modelHolidayPrices = dateListMap.values().stream().map(x->{
            if (x.size()>1){
                Optional<VehicleModelHolidayPrice> holidayPrice = x.stream().sorted(Comparator.comparing(VehicleModelHolidayPrice::getMultiple).reversed()).findFirst();
                return Lists.newArrayList(holidayPrice.get());
            }else {
                return x;
            }
        }).flatMap(List::stream).collect(Collectors.toList());

        VehicleModelHolidayPriceDTO vehicleModelHolidayPriceDTO;
        for (VehicleModelHolidayPrice modelHolidayPrice : modelHolidayPrices) {
            vehicleModelHolidayPriceDTO = new VehicleModelHolidayPriceDTO();
            BeanUtils.copyProperties(modelHolidayPrice, vehicleModelHolidayPriceDTO);
            vehicleModelHolidayPriceDTO.setFestival((festivalMap==null || null == festivalMap.get(modelHolidayPrice.getFestivalId()))?"":festivalMap.get(modelHolidayPrice.getFestivalId()).getName());
            vehicleModelHolidayPriceDTOS.add(vehicleModelHolidayPriceDTO);
        }
        return vehicleModelHolidayPriceDTOS;
    }

    /**
     * @param id
     * @return
     */
    public VehicleModelHolidayPriceSaveDTO findVehicleModelHolidayPriceFestivalId(Long id) {
        VehicleModelHolidayPriceSaveDTO modelHolidayPriceSaveDTO = new VehicleModelHolidayPriceSaveDTO();
        Example example = new Example(VehicleModelHolidayPrice.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("festivalId",id);
        List<VehicleModelHolidayPrice> vehicleModelHolidayPrices = mapper.selectByExample(example);
        if (CollectionUtils.isEmpty(vehicleModelHolidayPrices)) {
            throw new BaseException("数据不存在");
        }
        Date startDate = vehicleModelHolidayPrices.stream().map(VehicleModelHolidayPrice::getFestivalDay).min(Date::compareTo).get();
        Date endDate = vehicleModelHolidayPrices.stream().map(VehicleModelHolidayPrice::getFestivalDay).max(Date::compareTo).get();
        VehicleModelHolidayPrice vehicleModelHolidayPrice = vehicleModelHolidayPrices.get(0);
        BeanUtils.copyProperties(vehicleModelHolidayPrice, modelHolidayPriceSaveDTO);
        modelHolidayPriceSaveDTO.setStartDate(startDate);
        modelHolidayPriceSaveDTO.setEndDate(endDate);
        return modelHolidayPriceSaveDTO;
    }

    public void deleteById(Integer festivalId){
        Example example = new Example(VehicleModelHolidayPrice.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("festivalId",festivalId);
        VehicleModelHolidayPrice vehicleModelHolidayPrice = new VehicleModelHolidayPrice();
        vehicleModelHolidayPrice.setIsDel(1);
        mapper.updateByExampleSelective(vehicleModelHolidayPrice,example);
        festivalBiz.deleteById(festivalId);
    }

    /**
     * 设置查询条件日期
     *
     * @param conditionDate
     * @param criteria
     */
    private void setCondtionDate(Date conditionDate, Integer year, Example.Criteria criteria) {
        //开始日期
        Instant startInstant = null;
        //结束日期
        Instant endInstant = null;
        if (Objects.nonNull(year) && Objects.isNull(conditionDate)) {
            startInstant = LocalDate.of(year, 1, 1).atStartOfDay(ZoneId.systemDefault()).toInstant();
            endInstant = LocalDate.of(year, 12, 31).atStartOfDay(ZoneId.systemDefault()).toInstant();
        }
        if (Objects.nonNull(conditionDate)) {
            LocalDate localDate = conditionDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            startInstant = localDate.withDayOfMonth(1).atStartOfDay(ZoneId.systemDefault()).toInstant();
            LocalDate endLocalDate = localDate.with(TemporalAdjusters.lastDayOfMonth());
            endInstant = endLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant();
        }
        if (Objects.nonNull(startInstant) && Objects.nonNull(endInstant)) {
            criteria.andBetween("festivalDay", Date.from(startInstant), Date.from(endInstant));
        }
    }

}
