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.ObjUtil;
import cn.hutool.core.util.StrUtil;
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.depttype.vo.IotDeptTypePageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotprojectinfo.vo.IotProjectInfoPageReqVO;
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.controller.admin.iotrydailyreport.vo.IotRyDailyReportPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.vo.IotDevicePageReqVO;
import cn.iocoder.yudao.module.pms.dal.dataobject.IotDeviceDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.depttype.IotDeptTypeDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojectinfo.IotProjectInfoDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttask.IotProjectTaskDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotrydailyreport.IotRyDailyReportDO;
import cn.iocoder.yudao.module.pms.dal.mysql.IotDeviceMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.depttype.IotDeptTypeMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotrydailyreport.IotRyDailyReportMapper;
import cn.iocoder.yudao.module.pms.message.PmsMessage;
import cn.iocoder.yudao.module.pms.service.iotmainworkorderbom.IotMainWorkOrderBomService;
import cn.iocoder.yudao.module.pms.service.iotprojectinfo.IotProjectInfoService;
import cn.iocoder.yudao.module.pms.service.iotprojecttask.IotProjectTaskService;
import cn.iocoder.yudao.module.pms.service.iotrydailyreport.IotRyDailyReportService;
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.LocalDateTime;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

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 CreateRyZjDailyReportOrderJob implements JobHandler {
    @Resource
    private IotProjectInfoService iotProjectInfoService;
    @Resource
    private IotRyDailyReportMapper iotRyDailyReportMapper;
    @Autowired
    private IotRyDailyReportService iotRyDailyReportService;

    @Autowired
    private IotDeviceMapper iotDeviceMapper;
    @Resource
    private IotProjectTaskService iotProjectTaskService;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private IotMainWorkOrderBomService iotMainWorkOrderBomService;
    @Resource
    private IotDeptTypeMapper iotDeptTypeMapper;
    @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 {

        // 查询瑞鹰下所有部门 筛选出 钻井 队伍(不包含任何设备的队伍)
        IotDeptTypePageReqVO deptTypeReqVO = new IotDeptTypePageReqVO();
        // 查询 钻井 类型的部门
        deptTypeReqVO.setType("zj");
        List<IotDeptTypeDO> deptTypes = iotDeptTypeMapper.selectList(deptTypeReqVO);
        Set<Long> zjDeptIds = new HashSet<>();
        // 无设备 的部门id集合
        Set<Long> affiliatedDeptIds = new HashSet<>();
        // key部门id      value日报填报人id
        Map<Long, Long> affiliatedDeptIdUserIdPair = new HashMap<>();
        AtomicReference<String> creator = new AtomicReference<>(StrUtil.EMPTY);
        Set<String> usernames = new HashSet<>();
        // key用户username  value用户userId
        Map<String, Long> usernameIdPair = new HashMap<>();
        // key部门deptId  value用户username
        Map<Long, String> deptUsernamePair = new HashMap<>();
        // key部门deptId  value用户userId
        Map<Long, Long> deptUserIdPair = new HashMap<>();
        Long userId = 0l;
        if (CollUtil.isNotEmpty(deptTypes)) {
            deptTypes.forEach(deptType -> {
                zjDeptIds.add(deptType.getDeptId());
                // 部分部门的日报需要由固定的人填写 RYMQC
                if (StrUtil.isNotBlank(deptType.getCreator())) {
                    affiliatedDeptIds.add(deptType.getDeptId());
                    // creator.set(deptType.getCreator());
                    usernames.add(deptType.getCreator());
                    deptUsernamePair.put(deptType.getDeptId(), deptType.getCreator());
                }
            });
            // 根据 用户账号 查询用户id 无设备队伍 日报填报人
            if (CollUtil.isNotEmpty(usernames)) {
                List<AdminUserRespDTO> users = adminUserApi.getUserListByUsernames(usernames);
                if (CollUtil.isNotEmpty(users)) {
                    users.forEach(user -> {
                        usernameIdPair.put(user.getUsername(), user.getId());
                    });
                    // AdminUserRespDTO user = users.get(0);
                    // userId = user.getId();
                    // 设置部门与用户id对应关系
                    deptUsernamePair.forEach((deptId, username) -> {
                        if (usernameIdPair.containsKey(username)) {
                            Long tempUserId = usernameIdPair.get(username);
                            deptUserIdPair.put(deptId, tempUserId);
                        } else {
                            log.warn("用户名:{} 未找到对应的用户ID，部门ID:{}", username, deptId);
                        }
                    });
                }
            }
        }
        // 查询瑞鹰下所有队伍
        Set<Long> ryTeamDeptIds = new HashSet<>();
        // 查询瑞鹰所有 队伍 项目部
        Set<Long> ryChildDeptIds = deptService.getChildDeptIdListFromCache(158l);
        List<DeptDO> depts =deptService.getDeptList(ryChildDeptIds);
        if (CollUtil.isNotEmpty(depts)) {
            depts.forEach(dept -> {
                if ("3".equals(dept.getType())) {
                    ryTeamDeptIds.add(dept.getId());
                }
            });
        }
        // 查询瑞鹰所有队伍关联的设备 筛选出不包含任何设备的队伍
        IotDevicePageReqVO reqVO = new IotDevicePageReqVO();
        reqVO.setDeptIds(new ArrayList<>(ryTeamDeptIds));
        List<IotDeviceDO> devices = iotDeviceMapper.selectListAlone(reqVO);
        // 包含设备的部门id集合
        Set<Long> containsDeviceDeptIds = new HashSet<>();
        if (CollUtil.isNotEmpty(devices)) {
            devices.forEach(device -> {
                containsDeviceDeptIds.add(device.getDeptId());
            });
        }
        // 不包含任何设备的队伍id集合
        Set<Long> noDeviceZjDeptIds = zjDeptIds.stream()
                .filter(deptId -> !containsDeviceDeptIds.contains(deptId))
                .collect(Collectors.toSet());

        // 查询 无设备 钻井 队伍 日报列表
        IotRyDailyReportPageReqVO ryReqVO = new IotRyDailyReportPageReqVO();
        ryReqVO.setDeptIds(noDeviceZjDeptIds);
        ryReqVO.setProjectClassification("1");
        List<IotRyDailyReportDO> ryDailyReports = iotRyDailyReportMapper.dailyReports(ryReqVO);

        // 查询所有瑞鹰的项目任务 以‘部门-时间’ 为唯一键 当天创建时间 内没有生成过日报 就自动生成
        IotRdDailyReportPageReqVO pageReqVO = new IotRdDailyReportPageReqVO();
        LocalDateTime currentDate = LocalDateTime.now();
        String currentFormatDateStr = LocalDateTimeUtil.format(currentDate, "yyyy-MM-dd");
        // 前一天的日期
        LocalDateTime yesterday = currentDate.minusDays(1);
        // 当天已经生成日报的钻井队伍deptId集合
        Set<Long> currentDayReportedDeptIds = new HashSet<>();
        if (CollUtil.isNotEmpty(ryDailyReports)) {
            ryDailyReports.forEach(report -> {
                // 查询当天生成的日报
                LocalDateTime createDate = report.getCreateTime();
                String formatDateStr = LocalDateTimeUtil.format(createDate, "yyyy-MM-dd");
                if (formatDateStr.equals(currentFormatDateStr)) {
                    currentDayReportedDeptIds.add(report.getDeptId());
                }
            });
        }

        // 如果当天的钻井日报记录中不包含 无设备的钻井队伍部门id 则生成钻井队伍日报记录
        Set<Long> tobeReportZjDeptIds = noDeviceZjDeptIds.stream()
                .filter(deptId -> !currentDayReportedDeptIds.contains(deptId))
                .collect(Collectors.toSet());

        if (CollUtil.isNotEmpty(tobeReportZjDeptIds)) {
            // 查询这些部门对象集合
            Map<Long, DeptDO> deptMap = deptService.getDeptMap(tobeReportZjDeptIds);

            // 查询这些部门所有的项目任务 筛选未完工的任务
            IotProjectTaskPageReqVO taskReqVO = new IotProjectTaskPageReqVO();
            taskReqVO.setCompanyId(158l);
            taskReqVO.setJobFlag("Y");
            List<IotProjectTaskDO> tasks = iotProjectTaskService.projectTasks(taskReqVO);
            Map<Long, Set<Long>> taskDeptPair = new HashMap<>();
            // key任务id   value项目id
            Map<Long, Long> taskProjectPair = new HashMap<>();
            // key任务id   value井号
            Map<Long, String> taskWellNamePair = new HashMap<>();
            Set<Long> projectIds = new HashSet<>();
            if (CollUtil.isNotEmpty(tasks)) {
                tasks.forEach(task -> {
                    taskDeptPair.put(task.getId(), task.getDeptIds());
                    projectIds.add(task.getProjectId());
                    taskProjectPair.put(task.getId(), task.getProjectId());
                    taskWellNamePair.put(task.getId(), task.getWellName());
                });
            }
            Map<Long, IotProjectInfoDO> projectPair = new HashMap<>();
            if (CollUtil.isNotEmpty(projectIds)) {
                IotProjectInfoPageReqVO projectReqVO = new IotProjectInfoPageReqVO();
                projectReqVO.setProjectIds(new ArrayList<>(projectIds));
                List<IotProjectInfoDO> projects = iotProjectInfoService.getIotProjectInfos(projectReqVO);
                if (CollUtil.isNotEmpty(projects)) {
                    projects.forEach(project -> {
                        projectPair.put(project.getId(), project);
                    });
                }
            }

            List<IotRyDailyReportDO> tobeAddedReports = new ArrayList<>();
            for (Long tobeReportZjDeptId : tobeReportZjDeptIds) {
                IotRyDailyReportDO noDeviceReport = new IotRyDailyReportDO();
                noDeviceReport.setDeptId(tobeReportZjDeptId);
                noDeviceReport.setProjectClassification("1");
                if (affiliatedDeptIds.contains(tobeReportZjDeptId)) {
                    // 无设备队伍 的日报
                    if (deptUserIdPair.containsKey(tobeReportZjDeptId)) {
                        noDeviceReport.setCreator(String.valueOf(deptUserIdPair.get(tobeReportZjDeptId)));
                    }
                } else {
                    // 综合队等其它挂靠修井队
                    if (CollUtil.isNotEmpty(deptMap) && deptMap.containsKey(tobeReportZjDeptId)) {
                        DeptDO dept = deptMap.get(tobeReportZjDeptId);
                        if (ObjUtil.isNotEmpty(dept.getLeaderUserId())) {
                            noDeviceReport.setCreator(String.valueOf(dept.getLeaderUserId()));
                        }
                    }
                }
                // 设置日报的项目任务信息
                if (CollUtil.isNotEmpty(taskDeptPair)) {
                    taskDeptPair.forEach((taskId, deptIds) -> {
                        if (deptIds.contains(tobeReportZjDeptId)) {
                            noDeviceReport.setTaskId(taskId);
                            // 设置任务对应的项目信息
                            if (taskProjectPair.containsKey(taskId)) {
                                noDeviceReport.setProjectId(taskProjectPair.get(taskId));
                            }
                        }
                    });
                }
                tobeAddedReports.add(noDeviceReport);
            }

            if (CollUtil.isNotEmpty(tobeAddedReports)) {
                iotRyDailyReportMapper.insertBatch(tobeAddedReports);

                // 异步发送消息提醒 钉钉 站内信
                // 查询所有日报的创建人 userId 集合
                Set<Long> userIds = new HashSet<>(convertList(tobeAddedReports, report -> Long.valueOf(report.getCreator())));
                Map<Long, AdminUserRespDTO> users = adminUserApi.getUserMap(userIds);
                // 建立日报与 用户手机号的 对应关系
                Map<Long, String> reportMobilePair = new HashMap<>();
                tobeAddedReports.forEach(report -> {
                    if (users.containsKey(Long.valueOf(report.getCreator()))) {
                        AdminUserRespDTO user = users.get(Long.valueOf(report.getCreator()));
                        reportMobilePair.put(report.getId(), user.getMobile());
                    }
                });
                // 异步多线程发送 站内信 钉钉 消息
                tobeAddedReports.forEach(report -> {
                    CountDownLatch latch = new CountDownLatch(tobeAddedReports.size());
                    // deptMap 部门集合   taskWellNamePair任务集合
                    Long deptId = report.getDeptId();
                    DeptDO dept = deptMap.get(deptId);
                    String msgTitle = dept.getName();
                    Long taskId = report.getTaskId();
                    if (ObjUtil.isNotEmpty(taskId)) {
                        String wellName = taskWellNamePair.get(taskId);
                        msgTitle = StrUtil.join("-", msgTitle, wellName);
                    }
                    String finalMsgTitle = msgTitle;
                    pmsThreadPoolTaskExecutor.execute(() -> {
                        try {
                            if (reportMobilePair.containsKey(report.getId())) {
                                String mobile = reportMobilePair.get(report.getId());
                                pmsMessage.sendMessage(report.getId(), finalMsgTitle, PmsConstants.RY_DAILY_REPORT,
                                        Long.valueOf(report.getCreator()), mobile);
                            }
                        } finally {
                            latch.countDown();
                        }
                    });
                });

            }
        }
        return "创建成功";
    }
}
