package cn.iocoder.yudao.module.pms.job.dailyreport;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.pms.constant.PmsConstants;
import cn.iocoder.yudao.module.pms.controller.admin.iotprojecttask.vo.IotProjectTaskPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotrddailyreport.vo.IotRdDailyReportPageReqVO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttask.IotProjectTaskDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotrddailyreport.IotRdDailyReportDO;
import cn.iocoder.yudao.module.pms.message.PmsMessage;
import cn.iocoder.yudao.module.pms.service.iotdeviceperson.IotDevicePersonService;
import cn.iocoder.yudao.module.pms.service.iotmaintenancebom.IotMaintenanceBomService;
import cn.iocoder.yudao.module.pms.service.iotmainworkorderbom.IotMainWorkOrderBomService;
import cn.iocoder.yudao.module.pms.service.iotprojecttask.IotProjectTaskService;
import cn.iocoder.yudao.module.pms.service.iotrddailyreport.IotRdDailyReportService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.CountDownLatch;

import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.module.pms.framework.config.MultiThreadConfiguration.PMS_THREAD_POOL_TASK_EXECUTOR;

@Component
@Slf4j
public class CreateRdDailyReportOrderJob implements JobHandler {
    @Resource
    private IotDevicePersonService iotDevicePersonService;
    @Resource
    private IotMaintenanceBomService iotMaintenanceBomService;
    @Autowired
    private IotRdDailyReportService iotRdDailyReportService;

    @Resource
    private IotProjectTaskService iotProjectTaskService;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private IotMainWorkOrderBomService iotMainWorkOrderBomService;

    @Resource(name = PMS_THREAD_POOL_TASK_EXECUTOR)
    private ThreadPoolTaskExecutor pmsThreadPoolTaskExecutor;
    @Resource
    private PmsMessage pmsMessage;
    @Resource
    private DeptService deptService;

    @Override
    @TenantIgnore
    public String execute(String param) throws Exception {

        // 查询 SAP同步领料单 开始时间 结束时间 数据字典
        String createTime = DictFrameworkUtils.parseDictDataValue("rq_iot_rd_daily_report_createtime", "生成时间");

        // 查询所有瑞都的项目任务 以‘井号-时间’ 为唯一键 当天创建时间 内没有生成过日报 就自动生成
        IotRdDailyReportPageReqVO pageReqVO = new IotRdDailyReportPageReqVO();
        List<IotRdDailyReportDO> dailyReports = iotRdDailyReportService.dailyReports(pageReqVO);
        LocalDateTime currentDate = LocalDateTime.now();
        String currentFormatDateStr = LocalDateTimeUtil.format(currentDate, "yyyy-MM-dd");
        // 前一天的日期
        LocalDateTime yesterday = currentDate.minusDays(1);
        // 次日的日期
        LocalDateTime nextDay = currentDate.plusDays(1);
        // 需要生成日报的 任务(井号) 集合
        Set<Long> taskIds = new HashSet<>();
        if (CollUtil.isNotEmpty(dailyReports)) {
            dailyReports.forEach(report -> {
                // 查询当天生成的日报
                LocalDateTime createDate = report.getCreateTime();
                String formatDateStr = LocalDateTimeUtil.format(createDate, "yyyy-MM-dd");
                if (formatDateStr.equals(currentFormatDateStr)) {
                    taskIds.add(report.getTaskId());
                }
            });
        }
        
        // 查询瑞都相关的项目任务 根据每个任务的填报人进行工单生成和推送
        // 平台井任务只生成主井号任务 关联井在日报中聚合处理
        IotProjectTaskPageReqVO taskReqVO = new IotProjectTaskPageReqVO();
        taskReqVO.setCompanyId(163l);
        taskReqVO.setJobFlag("Y");
        List<IotProjectTaskDO> tasks = iotProjectTaskService.projectTasks(taskReqVO);
        // 平台井任务关联了3口井，其中2口井已经完工，1口井还在施工，平台井任务需要定时生成日报
        // 从任务列表中筛选出 (platformWell=0或platformGroup有值)的记录，并进一步找到 platformGroup有值的记录 对应的‘主井记录’生成日报
        List<IotProjectTaskDO> qualifiedTasks = new ArrayList<>();
        Set<String> platformGroups = new HashSet<>();
        // 未施工完成的任务id集合
        Set<Long> unfinishedTaskIds = new HashSet<>();
        // key平台井标识platformGroup    value平台井platformWell=1时的taskId
        Map<String, IotProjectTaskDO> mainWellTaskPair = new HashMap<>();
        if (CollUtil.isNotEmpty(tasks)) {
            tasks.forEach(task -> {
                // 非平台井任务 直接生成日报
                qualifiedTasks.add(task);
                if (StrUtil.isNotBlank(task.getPlatformGroup())) {
                    platformGroups.add(task.getPlatformGroup());
                    if (1 == task.getPlatformWell()) {
                        mainWellTaskPair.put(task.getPlatformGroup(), task);
                    }
                }
                // 生成所有所有未施工完成的任务id集合
                unfinishedTaskIds.add(task.getId());
            });
            // 找出 关联井未施工完成 但是主井已经施工完成的记录 同步生成主井日报

            // 查询出 platformGroups 对应的任务，找到主井记录
            if (CollUtil.isNotEmpty(platformGroups)) {
                IotProjectTaskPageReqVO platformTaskReqVO = new IotProjectTaskPageReqVO();
                platformTaskReqVO.setPlatformGroups(new ArrayList<>(platformGroups));
                List<IotProjectTaskDO> platformTasks = iotProjectTaskService.projectTasks(platformTaskReqVO);
                if (CollUtil.isNotEmpty(platformTasks)) {
                    // platformTasks 可能同时包含 主井 关联井 有的已经施工完成 有的未施工完成
                    // 已经施工完成的关联井不再生成日报
                    // 未施工完成的关联井需要和相关主井一起生成日报
                    platformTasks.forEach(task -> {
                        /* if (2 == task.getPlatformWell() && !"wg".equals(task.getStatus())
                                && mainWellTaskPair.containsKey(task.getPlatformGroup()) && !unfinishedTaskIds.contains(task.getId())) {
                            qualifiedTasks.add(mainWellTaskPair.get(task.getPlatformGroup()));
                        } */
                        if (1 == task.getPlatformWell() && "wg".equals(task.getStatus())
                                && !mainWellTaskPair.containsKey(task.getPlatformGroup()) && !unfinishedTaskIds.contains(task.getId())) {
                            qualifiedTasks.add(task);
                        }
                    });
                }
            }
        }

        Set<Long> userIds = new HashSet<>();
        List<IotRdDailyReportDO> reports = new ArrayList<>();
        Map<Long, Long> taskSubmitterPair = new HashMap<>();
        // key任务id  value施工队伍id
        Map<Long, Long> taskTeamIdPair = new HashMap<>();
        Set<Long> teamDepartmentIds = new HashSet<>();
        if (CollUtil.isNotEmpty(qualifiedTasks)) {
            qualifiedTasks.forEach(task -> {
                // 查询当前任务的 工单填报人
                Set<Long> submitterIds = task.getSubmitter();
                Set<Long> teamDeptIds = task.getDeptIds();
                if (CollUtil.isNotEmpty(submitterIds)) {
                    // 查询工单填报人所在部门
                    userIds.addAll(submitterIds);
                    taskSubmitterPair.put(task.getId(), new ArrayList<>(submitterIds).get(0));
                }
                if (CollUtil.isNotEmpty(teamDeptIds)) {
                    taskTeamIdPair.put(task.getId(), new ArrayList<>(teamDeptIds).get(0));
                    teamDepartmentIds.addAll(teamDeptIds);
                }
            });
            // 查询所有任务配置的工单填报人的信息
            Map<Long, AdminUserRespDTO> users = adminUserApi.getUserMap(userIds);
            Set<Long> deptIds = new HashSet<>();
            if (CollUtil.isNotEmpty(users)) {
                // 统一查询所有用户所属的部门信息
                users.forEach((userId, user) -> {
                    deptIds.add(user.getDeptId());
                });
            }
            // 查询所有任务施工队伍的 deptId
            Map<Long, DeptDO> deptPair = deptService.getDeptMap(teamDepartmentIds);
            // 以任务为维度 生成瑞都日报 部门为任务配置的工单填报人对应的部门
            // todo 任务填报人列表中 如果有人属于队伍上 则 设置日报deptId=队伍id 这样项目部填报人也能看到日报
            qualifiedTasks.forEach(task -> {
                if (!taskIds.contains(task.getId()) && CollUtil.isNotEmpty(task.getSubmitter())) {
                    // 生成当天的日报
                    IotRdDailyReportDO report = new IotRdDailyReportDO();
                    if (taskSubmitterPair.containsKey(task.getId())) {
                        Long userId = taskSubmitterPair.get(task.getId());
                        if (users.containsKey(userId)) {
                            AdminUserRespDTO user = users.get(userId);
                            // 取任务施工队伍的 deptId
                            if (taskTeamIdPair.containsKey(task.getId())) {
                                report.setDeptId(taskTeamIdPair.get(task.getId()));
                            } else {
                                report.setDeptId(user.getDeptId());
                            }
                            // 根据用户部门名称 生成日报标题
                            if (deptPair.containsKey(report.getDeptId())) {
                                DeptDO dept = deptPair.get(report.getDeptId());
                                String deptName = dept.getName();
                                String[] multiLangDeptNames = deptName.split("~~");
                                report.setReportName(multiLangDeptNames[0] + "/" + currentFormatDateStr + "日报" );
                            }
                        }
                    }

                    // 修改开始：创建专门用于日报的日期时间，将时分秒固定为08:00:00
                    // 将日期部分保持不变，时间部分设置为08:00:00
                    LocalDate currentLocalDate = currentDate.toLocalDate();
                    LocalDate nextLocalDate = nextDay.toLocalDate();

                    LocalDateTime dailyReportStartTime = LocalDateTime.of(currentLocalDate, LocalTime.of(8, 0, 0));
                    LocalDateTime dailyReportEndTime = LocalDateTime.of(nextLocalDate, LocalTime.of(8, 0, 0));

                    report.setProjectId(task.getProjectId());
                    report.setTaskId(task.getId());
                    report.setPlatformWell(task.getPlatformWell());
                    report.setPlatformGroup(StrUtil.EMPTY);
                    report.setTaskPlatform(task.getPlatformGroup());
                    report.setDeviceIds(task.getDeviceIds());
                    report.setStartTime(LocalTime.of(8, 0, 0));
                    report.setEndTime(LocalTime.of(8, 0, 0));
                    report.setConstructionStartDate(dailyReportStartTime);
                    report.setConstructionEndDate(dailyReportEndTime);
                    Set<Long> submitters = task.getSubmitter();
                    report.setCreator(String.valueOf(new ArrayList<>(submitters).get(0)));
                    report.setCreateTime(LocalDateTime.now());
                    reports.add(report);
                }
            });
        }
        if (CollUtil.isNotEmpty(reports)) {
            Map<String, List<IotRdDailyReportDO>> platformPair = new HashMap<>();
            // 替换 日报的 platformGroup 以区分不同的任务
            reports.forEach(report -> {
                String taskPlatform = report.getTaskPlatform();
                if (StrUtil.isNotBlank(taskPlatform)) {
                    if (platformPair.containsKey(taskPlatform)) {
                        List<IotRdDailyReportDO> tempReports = platformPair.get(taskPlatform);
                        tempReports.add(report);
                        platformPair.put(taskPlatform, tempReports);
                    } else {
                        List<IotRdDailyReportDO> tempReports = new ArrayList<>();
                        tempReports.add(report);
                        platformPair.put(taskPlatform, tempReports);
                    }
                }
            });
            if (CollUtil.isNotEmpty(platformPair)) {
                platformPair.forEach((taskPlatform, platformReports) -> {
                    // 相同的任务 如果是平台井 则重新生成 uuid 不利用项目任务的uuid
                    String tempUuid = StrUtil.uuid();
                    platformReports.forEach(report -> {
                        report.setPlatformGroup(tempUuid);
                    });
                });
            }
            iotRdDailyReportService.batchAddDailyReports(reports);
        }

        // 向日报 填报人 发送 站内信及 钉钉消息
        if (CollUtil.isNotEmpty(reports)) {
            List<IotRdDailyReportDO> msgReports = new ArrayList<>();
            // 如果日报是平台井 只发送主井任务
            reports.forEach(report -> {
                if (1 == report.getPlatformWell() || 0 == report.getPlatformWell()) {
                    msgReports.add(report);
                }
            });
            // 先查询所有 日报填报人的手机号
            Set<Long> personIds = new HashSet<>(convertList(msgReports, report -> Long.valueOf(report.getCreator())));
            Map<Long, AdminUserRespDTO> users = adminUserApi.getUserMap(personIds);
            // 建立日报与 用户手机号的 对应关系
            Map<Long, String> orderMobilePair = new HashMap<>();
            msgReports.forEach(report -> {
                if (users.containsKey(Long.valueOf(report.getCreator()))) {
                    AdminUserRespDTO user = users.get(Long.valueOf(report.getCreator()));
                    orderMobilePair.put(report.getId(), user.getMobile());
                }
            });
            // 异步多线程发送 站内信 钉钉 消息
            msgReports.forEach(order -> {
                CountDownLatch latch = new CountDownLatch(msgReports.size());
                pmsThreadPoolTaskExecutor.execute(() -> {
                    try {
                        if (orderMobilePair.containsKey(order.getId())) {
                            String mobile = orderMobilePair.get(order.getId());
                            pmsMessage.sendMessage(order.getId(), order.getReportName(), PmsConstants.DAILY_REPORT,
                                    Long.valueOf(order.getCreator()), mobile);
                        }
                    } finally {
                        latch.countDown();
                    }
                });
            });
        }
        return "创建成功";
    }
}
