package com.bonus.system.att.tasks;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.bonus.common.core.utils.DateTimeHelper;
import com.bonus.common.core.utils.DateUtils;
import com.bonus.system.att.dao.AttGroupDao;
import com.bonus.system.att.dao.AttSourceDataDao;
import com.bonus.system.att.entity.*;
import com.bonus.system.att.service.AttCalService;
import com.bonus.system.att.utils.AddressCoordinateFormatUtil;
import com.bonus.system.att.utils.AttTimeUtil;
import com.bonus.system.att.utils.WorkdayCalculator;
import com.bonus.system.holiday.dao.HolidayDao;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import javax.annotation.Resource;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @author zys
 * 考勤定时器
 */
@Configuration
@EnableScheduling
@Slf4j
@EnableAsync
public class NewAttTask {

    @Resource(name = "AttCalService")
    private AttCalService attCalService;

    /**
     * 考勤模版数据定时器 凌晨10分启动一次，一天仅仅一次
     */
    @Scheduled(cron = "0 10 0 * * ?")
//    @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10)
    @Async
    public void getAttTempDataTask() {
        log.info("--------考勤模版数据定时器开启------");
        String today = DateUtil.today();
        insertAttDateHistory(today);
        insertAttTempData(today,1);
        log.info("--------考勤模版数据定时器完毕------");
    }


    /**
     * 1.数据拉取（考勤）定时器 每隔1个小时获取一次数据(从早上 5 点开始，每小时执行一次)
     * 2.考勤数据应用（步骤一：考勤数据更新）
     */
    @Scheduled(cron = "0 0 5-23 * * ?")
//    @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10)
    @Async
    public void getAttDataPullTask() {
        log.info("--------数据拉取（考勤）定时器开启------");
        String today = DateUtil.today();
        getAttendanceData(today,1);
        updateAttData(today,1);
        log.info("--------数据拉取（考勤）定时器完毕------");
    }

    /**
     * 单独子流程，不在主流程中
     * 旷工判断
     * 每天12点将当天未打卡考勤人员上班置为旷工
     * 每天晚上22点，将下班未打卡置为旷工
     */
    @Scheduled(cron = "0 0 12,22 * * ?")
//    @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10)
    @Async
    public void getAbsenteeismDataTask() {
        log.info("--------旷工判断定时器开启------");
        String today = DateUtil.today();
        updateAbsenteeismData(today,1);
        log.info("--------旷工判断定时器完毕------");
    }

    /**
     * 单独子流程，不在主流程中
     * 昨日下班卡更新
     * 每天7点将昨天数据更新一下
     */
    @Scheduled(cron = "0 0 7 * * ?")
//    @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10)
    @Async
    public void getYesterdayAttDataTask() {
        log.info("--------昨日下班卡更新定时器开启------");
        // 获取昨天日期
        LocalDate yesterday = LocalDate.now().minusDays(1);
        // 格式化输出
        String yesterdayStr = yesterday.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        updateAttData(yesterdayStr,2);
        //日报表更新 TODO
        log.info("--------昨日下班卡更新定时器完毕------");
    }

    /**
     * 请假数据应用--法假
     * 每天更新一次一点更新
     */
    @Scheduled(cron = "0 0 1 * * ?")
//    @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10)
    @Async
    public void getLegalHolidayDataTask() {
        log.info("--------请假数据应用--法假定时器开启------");
        String today = DateUtil.today();
        updateLegalHolidayData(today);
        log.info("--------请假数据应用--法假定时器完毕------");
    }

    /**
     * 请假数据应用--请假
     * 每天更新两次上午8点，下午18点（45天前数据）
     */
    @Scheduled(cron = "0 0 8,18 * * ?")
//    @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10)
    @Async
    public void getLeaveDataTask() {
        log.info("--------请假数据应用--请假定时器开启------");
        String today = DateUtil.today();
        updateLeaveData(today);
        log.info("--------请假数据应用--请假定时器完毕------");
    }


    /**
     * 报表数据生成--日报表
     * 6点10分开始,一小时更新一次
     */
    @Scheduled(cron = "0 10 6-23 * * ?")
//    @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10)
    @Async
    public void getDayReportDataTask() {
        log.info("--------报表数据生成--日报表定时器开启------");
        String today = DateUtil.today();
        insertDayReportData(today);
        log.info("--------报表数据生成--日报表定时器完毕------");
    }


    /**
     * 报表数据生成--月报表
     * 月初生成，之后修改
     */
    @Scheduled(cron = "0 15 1 1 * ?")
//    @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10)
    @Async
    public void getMonthReportDataTempTask() {
        log.info("--------报表数据生成--月报表定时器开启------");
        String today = DateUtil.today();
        insertMonthReportTempData(today);
        log.info("--------报表数据生成--月报表定时器完毕------");
    }

    /**
     * 报表数据生成--月报表
     * 每日数据变化修改之后修改
     */
    @Scheduled(cron = "0 0 8,10,17,19,23 * * ?")
//    @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10)
    @Async
    public void getMonthReportDataTask() {
        log.info("--------报表数据生成--月报表定时器开启------");
        String today = DateUtil.today();
        updateMonthReportData(today);
        log.info("--------报表数据生成--月报表定时器完毕------");
    }



    /**
     * 待考勤人员列表
     * 在人员考勤模版数据之前生成
     * @param pushDate 时间(可为空，为空则推历史60天内没生成的数据，不为空则推指定日期)
     */
    public void insertAttDateHistory(String pushDate) {
        //待考勤人员列表生成
        attCalService.insertAttDateHistory(pushDate);
    }


    /**
     * 人员考勤模版数据（默认是未打卡）
     * 每天早上0点30执行一次
     * @param pushDate 时间
     * @param pushType 1:自动推送（当天） 2:手动（历史）
     */
    public void insertAttTempData(String pushDate, int pushType) {
        //获取考勤数据
        attCalService.insertAttTempData(pushDate, pushType);
    }

    /**
     * 获取其他系统考勤数据
     * 建议一小时一次
     * @param pushDate 时间
     * @param pushType 1:自动推送（当天） 2:手动（历史）
     */
    public void getAttendanceData(String pushDate, int pushType) {
        //获取考勤数据
        attCalService.getAttendanceData(pushDate, pushType);
    }

    /**
     * 考勤数据应用（步骤一：考勤数据更新）
     * 建议一小时一次,紧随数据拉取之后
     * @param pushDate 时间
     * @param pushType 1:自动推送（当天） 2:手动（历史）
     */
    public void updateAttData(String pushDate, int pushType) {
        //获取考勤数据
        attCalService.updateAttData(pushDate, pushType);
    }

    /**
     * 考勤数据应用（步骤二：旷工状态更新）
     * 每天12点将当天未打卡考勤人员上班置为旷工
     * 每天晚上22点，将下班未打卡置为旷工
     * @param pushDate 时间
     * @param pushType 1:自动推送（当天） 2:手动（历史）
     */
    public void updateAbsenteeismData(String pushDate, int pushType) {
        //旷工状态更新
        attCalService.updateAbsenteeismData(pushDate, pushType);
    }

    /**
     * 请假数据应用（步骤一：法假数据更新）
     * 法定节假日不会随时间变化，一天执行一次就可以了
     * @param pushDate 时间
     */
    public void updateLegalHolidayData(String pushDate) {
        //法假数据更新
        attCalService.updateLegalHolidayData(pushDate);
    }

    /**
     * 请假数据应用（步骤二：请假数据更新）
     * 法定节假日不会随时间变化，一天执行一次就可以了
     * @param pushDate 时间
     */
    public void updateLeaveData(String pushDate) {
        //请假数据更新
        attCalService.updateLeaveData(pushDate);
    }

    /**
     * 报表数据生成（日报表）
     * 每次更新数据都要执行(跟随)
     * @param pushDate 时间
     */
    public void insertDayReportData(String pushDate) {
        //日报表更新
        attCalService.insertDayReportData(pushDate);
    }

    /**
     * 月报表数据生成（人员对应出月出勤）
     * 月初生成一次
     * @param pushDate 时间
     */
    public void insertMonthReportTempData(String pushDate) {
        //月报表模版数据生成
        attCalService.insertMonthReportTempData(pushDate);
    }

    /**
     * 月报表数据更新（人员对应出月出勤）
     * 每次更新完数据要执行(跟随)
     * @param pushDate 时间
     */
    public void updateMonthReportData(String pushDate) {
        //月报表模版数据生成
        attCalService.updateMonthReportData(pushDate);
    }

}