package cn.iocoder.yudao.module.system.job.holiday;

import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaybalancesetting.HolidayBalanceSettingDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaysetting.HolidaySettingDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaysettingrange.HolidaySettingRangeDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidayworkingage.HolidayWorkingAgeDO;
import cn.iocoder.yudao.module.system.service.holiday.holidaybalancesetting.HolidayBalanceSettingService;
import cn.iocoder.yudao.module.system.service.holiday.holidaysetting.HolidaySettingService;
import cn.iocoder.yudao.module.system.service.holiday.holidaysettingrange.HolidaySettingRangeService;
import cn.iocoder.yudao.module.system.service.holiday.holidayuserrecord.HolidayUserRecordService;
import cn.iocoder.yudao.module.system.service.holiday.holidayworkingage.HolidayWorkingAgeService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Component
@Slf4j
public class HolidayGrantJob {

    @Resource
    private HolidayBalanceSettingService holidayBalanceSettingService;
    @Resource
    private HolidaySettingService holidaySettingService;
    @Resource
    private HolidayUserRecordService holidayUserRecordService;
    @Resource
    private HolidaySettingRangeService holidaySettingRangeService;
    @Resource
    private HolidayWorkingAgeService holidayWorkingAgeService;

    @XxlJob("holidayGrantJob")
    @TenantJob // --- ⚠️ 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意
    public ReturnT<String> execute() throws Exception {
        // -- 发放假期定时任务 - 每天凌晨4点执行一次 判断下是不是该发放了
        log.info("开始 发放假期");
        // -- 先获取所有假期余额设置
        LocalDateTime now = LocalDateTime.now();
        List<HolidayBalanceSettingDO> list = holidayBalanceSettingService.list(new LambdaQueryWrapper<HolidayBalanceSettingDO>()
                .eq(HolidayBalanceSettingDO::getStatus, 1)
                .in(HolidayBalanceSettingDO::getType, Arrays.asList(1, 2)));
        if (CollectionUtil.isEmpty(list)) {
            log.info("结束 发放假期");
            return ReturnT.SUCCESS;
        }

        List<Long> holidaySettingIds = list.stream().map(HolidayBalanceSettingDO::getHolidaySettingId).collect(Collectors.toList());
        List<HolidaySettingDO> holidaySettingDOS = holidaySettingService.listByIds(holidaySettingIds);
        Map<Long, HolidaySettingDO> holidaySettingMap = holidaySettingDOS.stream().collect(Collectors.toMap(HolidaySettingDO::getId, holidaySettingDO -> holidaySettingDO));

        List<HolidaySettingRangeDO> holidaySettingRangeDOS = holidaySettingRangeService.getListByHolidaySettingIds(holidaySettingIds);
        Map<Long, List<HolidaySettingRangeDO>> holidaySettingRangeMap = holidaySettingRangeDOS.stream().collect(Collectors.groupingBy(HolidaySettingRangeDO::getHolidaySettingId, Collectors.toList()));

        List<HolidayWorkingAgeDO> holidayWorkingAgeDOS = holidayWorkingAgeService.selectBySettingIds(holidaySettingIds);
        Map<Long, List<HolidayWorkingAgeDO>> holidayWorkingAgeDOMap = holidayWorkingAgeDOS.stream().collect(Collectors.groupingBy(HolidayWorkingAgeDO::getHolidaySettingId, Collectors.toList()));

        List<HolidayBalanceSettingDO> editList = new ArrayList<>();
        // -- 过滤出 按月发放 or 按每年一月一号 发放 的并且时间到了的
        List<HolidayBalanceSettingDO> fixedGrantList = list.stream().filter(holidayBalanceSettingDO ->
                (holidayBalanceSettingDO.getType() == 1 || (holidayBalanceSettingDO.getType() == 2 && holidayBalanceSettingDO.getIssueTimeType() == 2))
                        && holidayBalanceSettingDO.getIssueTime() != null
                        && holidayBalanceSettingDO.getIssueTime().isBefore(now)).collect(Collectors.toList());

        if (CollectionUtil.isNotEmpty(fixedGrantList)) {
            for (HolidayBalanceSettingDO holidayBalanceSettingDO : fixedGrantList) {
                // 计算下一次发放日期
                LocalDateTime issueTime = holidaySettingService.calculateNextReleaseDate(now, holidayBalanceSettingDO);
                holidayBalanceSettingDO.setIssueTime(issueTime);
                editList.add(holidayBalanceSettingDO);
                Long holidaySettingId = holidayBalanceSettingDO.getHolidaySettingId();
                // 发放假期
                holidayUserRecordService.grant(holidaySettingMap.get(holidaySettingId), holidaySettingRangeMap.get(holidaySettingId),
                        holidayBalanceSettingDO, holidayWorkingAgeDOMap.get(holidaySettingId), false);
            }
        }
        // -- // 按照员工入职日 每年员工入职日
        List<HolidayBalanceSettingDO> employmentGrantList = list.stream().filter(holidayBalanceSettingDO ->
                (holidayBalanceSettingDO.getType() == 2 && holidayBalanceSettingDO.getIssueTimeType() == 1)).collect(Collectors.toList());
        // 判断 员工是否发放过年假了 - 下次发放时间设置为明年1月1号 - 如果 用户入职时间 小于 当前时间
        if (CollectionUtil.isNotEmpty(employmentGrantList)) {
            for (HolidayBalanceSettingDO holidayBalanceSettingDO : employmentGrantList) {
                Long holidaySettingId = holidayBalanceSettingDO.getHolidaySettingId();
                // 发放假期
                holidayUserRecordService.grant(holidaySettingMap.get(holidaySettingId), holidaySettingRangeMap.get(holidaySettingId),
                        holidayBalanceSettingDO, holidayWorkingAgeDOMap.get(holidaySettingId), false);
            }
        }
        if (CollectionUtil.isNotEmpty(editList)) {
            holidayBalanceSettingService.batchUpdate(editList);
        }

        log.info("结束 发放假期");
        // 返回执行成功
        return ReturnT.SUCCESS;
    }

}
