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

import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.template.WxMaMsgTemplateUtils;
import cn.iocoder.yudao.framework.common.template.dto.MessageUnreadReminderDTO;
import cn.iocoder.yudao.framework.common.template.vo.SubscribeMessageReqDTO;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.system.api.subscribe.SubscribeMessageSendApi;
import cn.iocoder.yudao.module.system.controller.admin.user.dto.UserDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.auth.AdminOauthUserOtherInfoDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
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.holidayuserrecord.HolidayUserRecordDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.job.holiday.dto.HolidayRemindDTO;
import cn.iocoder.yudao.module.system.service.auth.AdminOauthUserOtherInfoService;
import cn.iocoder.yudao.module.system.service.auth.dto.AdminOauthUserOtherInfoDTO;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
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.holidayuserrecord.HolidayUserRecordService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
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.*;
import java.util.stream.Collectors;

@Component
@Slf4j
public class HolidayRemindJob {

    @Resource
    private HolidayBalanceSettingService holidayBalanceSettingService;
    @Resource
    private HolidaySettingService holidaySettingService;
    @Resource
    private HolidayUserRecordService holidayUserRecordService;
    @Resource
    private AdminUserService adminUserService;
    @Resource
    private DeptService deptService;
    @Resource
    private SubscribeMessageSendApi subscribeMessageSendApi;
    @Resource
    private AdminOauthUserOtherInfoService adminOauthUserOtherInfoService;

    @XxlJob("holidayRemindJob")
    @TenantJob // --- ⚠️ 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意
    public ReturnT<String> execute() throws Exception {
        // -- 假期过期提醒 - 每天晚上8点执行一次 判断下是不是该提醒了
        log.info("开始 过期提醒");
        // -- 先获取所有假期余额设置
        LocalDateTime now = LocalDateTime.now();
        // 获取用户假期记录 中需要提醒的数据
        List<HolidayUserRecordDO> list = holidayUserRecordService.getHolidayRemind(now);
        List<Long> userIds = new ArrayList<>();
        Map<Long, List<HolidayUserRecordDO>> recordMap = new HashMap<>();
        List<Long> holidayBalanceSettingIds = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(list)) {
            userIds = list.stream().map(HolidayUserRecordDO::getUserId).distinct().collect(Collectors.toList());
            recordMap = list.stream().collect(Collectors.groupingBy(HolidayUserRecordDO::getHolidayBalanceSettingId));
            holidayBalanceSettingIds = list.stream().map(HolidayUserRecordDO::getHolidayBalanceSettingId).distinct().collect(Collectors.toList());
        }
        List<AdminUserDO> userList = new ArrayList<>();
        List<Long> deptIds = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(userIds)) {
            userList = adminUserService.getAllList(new UserDTO().setUserIds(userIds));
        }
        if (CollectionUtil.isNotEmpty(userList)) {
            deptIds = userList.stream().map(AdminUserDO::getDeptId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        }
        List<DeptDO> deptDOS = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(deptIds)) {
            deptDOS = deptService.getDeptList(deptIds);
        }
        List<Long> leaderUserIds = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(deptDOS)) {
            // -- 查询主管
            leaderUserIds = deptDOS.stream().map(DeptDO::getLeaderUserId).distinct().collect(Collectors.toList());
        }
        if (CollectionUtil.isNotEmpty(leaderUserIds)) {
            List<AdminUserDO> executiveDirectorUsers = adminUserService.getAllList(new UserDTO().setUserIds(leaderUserIds));
            userList.addAll(executiveDirectorUsers);
        }
        Map<Long, AdminUserDO> userMap = userList.stream().distinct().collect(Collectors.toMap(AdminUserDO::getId, adminUserDO -> adminUserDO));
        List<Long> allUserIds = new ArrayList<>(userMap.keySet());
        List<AdminOauthUserOtherInfoDO> adminOauthUserOtherInfoDOS = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(allUserIds)) {
            adminOauthUserOtherInfoDOS = adminOauthUserOtherInfoService.getOpenIdByCondition(new AdminOauthUserOtherInfoDTO()
                    .setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType())
                    .setUserIds(allUserIds)
                    .setStatus(CommonStatusEnum.ENABLE.getStatus()));
        }
        Map<Long, String> openIdMap = adminOauthUserOtherInfoDOS.stream().collect(Collectors.toMap(AdminOauthUserOtherInfoDO::getUserId, AdminOauthUserOtherInfoDO::getOpenId));
        Map<Long, AdminUserDO> leaderMap = new HashMap<>();
        for (DeptDO deptDO : deptDOS) {
            leaderMap.put(deptDO.getId(), userMap.get(deptDO.getLeaderUserId()));
        }
        List<HolidayBalanceSettingDO> holidayBalanceSettingDOS = new ArrayList<>();
        List<HolidaySettingDO> holidaySettingDOS = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(holidayBalanceSettingIds)) {
            holidayBalanceSettingDOS = holidayBalanceSettingService.getByIds(holidayBalanceSettingIds);
            holidaySettingDOS = holidaySettingService.listByIds(holidayBalanceSettingIds);
        }
        // 获取到假期余额设置 为了获取发送范围
        Map<Long, HolidaySettingDO> holidaySettingMap = holidaySettingDOS.stream().collect(Collectors.toMap(HolidaySettingDO::getId, holidaySettingDO -> holidaySettingDO));
        List<HolidayRemindDTO> holidayRemindDTOS = new ArrayList<>();
        for (HolidayBalanceSettingDO holidayBalanceSettingDO : holidayBalanceSettingDOS) {
            List<HolidayUserRecordDO> holidayUserRecordDOS = recordMap.get(holidayBalanceSettingDO.getId());
            for (HolidayUserRecordDO holidayUserRecordDO : holidayUserRecordDOS) {
                HolidayRemindDTO remindDTO = new HolidayRemindDTO();
                AdminUserDO user = userMap.get(holidayUserRecordDO.getUserId());
                if (user == null || openIdMap.get(user.getId()) == null) {
                    continue;
                }
                String name = holidaySettingMap.get(holidayBalanceSettingDO.getHolidaySettingId()) == null ? "" : holidaySettingMap.get(holidayBalanceSettingDO.getHolidaySettingId()).getName();
                if (holidayBalanceSettingDO.getReminderRange() == 1) {
                    remindDTO.setUserId(holidayUserRecordDO.getUserId());
                    remindDTO.setOpenId(openIdMap.get(user.getId()));
                    remindDTO.setMsg("您的" + name + "假期即将过期");
                    holidayRemindDTOS.add(remindDTO);
                } else if (holidayBalanceSettingDO.getReminderRange() == 2) {
                    // 获取到主管 - 这里获取主管需要查询到对应用户所在的部门 - 完了后 在获取部门中的userIds
                    AdminUserDO adminUserDO = leaderMap.get(user.getDeptId());
                    remindDTO.setUserId(adminUserDO.getId());
                    if (leaderMap.get(adminUserDO.getId()) == null || openIdMap.get(adminUserDO.getId()) == null) {
                        continue;
                    }
                    remindDTO.setOpenId(openIdMap.get(adminUserDO.getId()));
                    remindDTO.setMsg(user.getNickname() + "的" + name + "假期即将过期");
                    holidayRemindDTOS.add(remindDTO);
                } else {
                    remindDTO.setUserId(holidayUserRecordDO.getUserId());
                    remindDTO.setOpenId(openIdMap.get(user.getId()));
                    remindDTO.setMsg("您的" + name + "假期即将过期");
                    holidayRemindDTOS.add(remindDTO);

                    // 获取到主管 - 这里获取主管需要查询到对应用户所在的部门 - 完了后 在获取部门中的userIds
                    AdminUserDO adminUserDO = leaderMap.get(user.getDeptId());
                    remindDTO.setUserId(adminUserDO.getId());
                    if (leaderMap.get(adminUserDO.getId()) != null && openIdMap.get(adminUserDO.getId()) == null) {
                        remindDTO.setOpenId(openIdMap.get(adminUserDO.getId()));
                        remindDTO.setMsg(user.getNickname() + "的" + name + "假期即将过期");
                        holidayRemindDTOS.add(remindDTO);
                    }
                }
            }
        }
        holidayRemindDTOS = holidayRemindDTOS.stream().distinct().filter(a -> a.getOpenId() != null).collect(Collectors.toList());
        //  发送信息 -
        for (HolidayRemindDTO holidayRemindDTO : holidayRemindDTOS) {
            try {
                SubscribeMessageReqDTO dto = new WxMaMsgTemplateUtils().convertMessageUnreadReminder(new MessageUnreadReminderDTO()
                        .setOpenId(holidayRemindDTO.getOpenId())
                        .setMsgType("假期提醒")
                        .setSender("系统提醒")
                        .setComment(holidayRemindDTO.getMsg())
                        .setSendingTime(DateUtils.dateFormat(new Date(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND))
                        .setMiniProgramState("formal"));
                subscribeMessageSendApi.sendMaMsg(dto);
            } catch (Exception e) {
                log.error("发送假期过期提醒失败:{}", holidayRemindDTO);
            }
        }
        holidayUserRecordService.editReminder(list);
        if (CollectionUtil.isEmpty(list)) {
            log.info("结束 过期提醒");
            return ReturnT.SUCCESS;
        }
        log.info("结束 过期提醒");
        // 返回执行成功
        return ReturnT.SUCCESS;
    }

}
