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

import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.system.controller.admin.worklog.vo.form.LogFormRuleVO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.worklog.LogFormDO;
import cn.iocoder.yudao.module.system.dal.dataobject.worklog.LogRuleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.worklog.LogStatisticsDO;
import cn.iocoder.yudao.module.system.dal.dataobject.worklog.LogStatisticsRecordDO;
import cn.iocoder.yudao.module.system.dal.mysql.worklog.LogStatisticsMapper;
import cn.iocoder.yudao.module.system.dal.mysql.worklog.LogStatisticsRecordMapper;
import cn.iocoder.yudao.module.system.service.worklog.LogFormService;
import cn.iocoder.yudao.module.system.service.worklog.LogStatisticsRecordService;
import cn.iocoder.yudao.module.system.service.worklog.LogStatisticsService;
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.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j
public class LogStatisticsJob {
    @Resource
    private LogStatisticsService logStatisticsService;
    @Resource
    private LogFormService logFormService;
    @Resource
    private LogStatisticsMapper logStatisticsMapper;
    @Resource
    private LogStatisticsRecordService logStatisticsRecordService;
    @Resource
    private LogStatisticsRecordMapper logStatisticsRecordMapper;

    @XxlJob("logStatisticsJob")
    @TenantJob // --- ⚠️ 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意
    public ReturnT<String> execute() throws Exception {
        //获取参数
        //XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();
        //String jobParam = xxlJobContext.getJobParam();
        //获取模版列表 - 从缓存中拿 - 修改模版或者新增模版的时候 删除缓存 todo 这里后面改成从缓存获取数据
        List<LogFormRuleVO> list = logFormService.getLogFormRuleList();
        if (list.isEmpty()) {
            return ReturnT.SUCCESS;
        }
        // -- 要判断当前规则 是不是已经统计过了
        Date thisDate = new Date();
        String thisTime = DateUtils.dateFormat(thisDate, DateUtils.FORMAT_YEAR_MONTH_DAY);
        //获取模版列表
        List<Long> formIds = list.stream().map(LogFormRuleVO::getFormDO).map(LogFormDO::getId).collect(Collectors.toList());
        List<LogStatisticsRecordDO> statisticsRecordDOS = logStatisticsRecordService.getByFormIdsAndTime(formIds, thisTime);
        Map<Long, LogStatisticsRecordDO> map = statisticsRecordDOS.stream().collect(Collectors.toMap(LogStatisticsRecordDO::getFormId, v -> v, (k1, k2) -> k1));
        // -- 需要插入到统计中为提交 日志的记录
        List<LogStatisticsDO> statisticsDOS = new ArrayList<>();
        List<LogStatisticsRecordDO> saveRecordDO = new ArrayList<>();
        for (LogFormRuleVO item : list) {
            //拿到模版规则
            LogRuleDO logRuleDO = item.getRuleDO();
            LogFormDO logFormDO = item.getFormDO();
            if (logFormDO == null || logRuleDO == null) {
                continue;
            }
            if (logRuleDO.getType() == 1) {
                int weekNum = DateUtils.dayOfWeek(thisDate);
                List<String> weekDays = Arrays.asList(logRuleDO.getWeekDays().split(","));
                // -- 还没有到统计的时间/不需要统计 - 跳出循环
                if (!weekDays.contains(Integer.toString(weekNum)) || thisDate.getTime() < DateUtils.buildHHmmTime(logRuleDO.getStatisticalTime()).getTime()) {
                    continue;
                }
                // -- 统计时间到了 - 判断是否已经统计过了 - 只需要统计谁没有提交就行 - 把没提交的记录插入到统计表中 - 其他的在新增日志里面就插入到统计表即可
                this.unSubmittedRecord(statisticsDOS, saveRecordDO, map, logFormDO, thisTime, logRuleDO);
            } else if (logRuleDO.getType() == 2) {
                Date statisticalTime = DateUtils.buildWeekHHmmTime(logRuleDO.getStatisticalTime());
                // -- 还没有到统计的时间 - 跳出循环
                if (thisDate.getTime() < statisticalTime.getTime()) {
                    continue;
                }
                this.unSubmittedRecord(statisticsDOS, saveRecordDO, map, logFormDO, thisTime, logRuleDO);
            }
        }
        if (!statisticsDOS.isEmpty()) {
            logStatisticsMapper.insertBatch(statisticsDOS);
        }
        if (!saveRecordDO.isEmpty()) {
            logStatisticsRecordMapper.insertBatch(saveRecordDO);
        }
        // 返回执行成功
        return ReturnT.SUCCESS;
    }


    public void unSubmittedRecord(List<LogStatisticsDO> statisticsDOS, List<LogStatisticsRecordDO> saveRecordDO, Map<Long, LogStatisticsRecordDO> map, LogFormDO logFormDO, String thisTime,
                                  LogRuleDO logRuleDO) {
        // -- 统计时间到了 - 判断是否已经统计过了 - 只需要统计谁没有提交就行 - 把没提交的记录插入到统计表中 - 其他的在新增日志里面就插入到统计表即可
        LogStatisticsRecordDO logStatisticsRecordDO = map.get(logFormDO.getId());
        String commitTimeRange = logStatisticsService.getCommitTimeRange(logRuleDO);
        if (logStatisticsRecordDO == null || logStatisticsRecordDO.getStatisticsFlag() == 0) {
            List<AdminUserDO> users = logStatisticsService.getUnSubmittedUser(logFormDO.getId(), thisTime);
            for (AdminUserDO user : users) {
                LogStatisticsDO logStatisticsDO = new LogStatisticsDO();
                logStatisticsDO.setUserId(user.getId());
                logStatisticsDO.setFormId(logFormDO.getId());
                logStatisticsDO.setRuleId(logRuleDO.getId());
                logStatisticsDO.setDeptId(user.getDeptId());
                logStatisticsDO.setType(logRuleDO.getType());
                logStatisticsDO.setStatus(3);
                logStatisticsDO.setTime(thisTime);
                logStatisticsDO.setCommitTimeRange(commitTimeRange);
                statisticsDOS.add(logStatisticsDO);
            }
            // -- 记录当前以统计
            saveRecordDO.add(new LogStatisticsRecordDO().setFormId(logFormDO.getId())
                    .setRuleId(logRuleDO.getId()).setTime(thisTime).setStatisticsFlag(1));
        }
    }
}
