package com.cmeeting.job;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.thread.ThreadUtil;
import com.azure.core.credential.AccessToken;
import com.azure.core.credential.TokenRequestContext;
import com.azure.identity.ClientSecretCredential;
import com.azure.identity.ClientSecretCredentialBuilder;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cmeeting.config.StatisticsEmailPushProperties;
import com.cmeeting.constant.DeptCollect;
import com.cmeeting.constant.MeetingState;
import com.cmeeting.dto.UserDTO;
import com.cmeeting.email.EmailSender;
import com.cmeeting.mapper.primary.UserIdMapper;
import com.cmeeting.pojo.MeetingInfo;
import com.cmeeting.pojo.SysUserSyncCategory;
import com.cmeeting.pojo.UserId;
import com.cmeeting.pojo.WeComUser;
import com.cmeeting.service.*;
import com.cmeeting.service.impl.CimcService;
import com.cmeeting.util.RedisUtils;
import com.cmeeting.vo.StatisticsEmailPush;
import com.cmeeting.vo.TencentMeetingVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Component
@Slf4j
public class CmeetingJob {
    @Autowired
    private WeComService weComService;
    @Autowired
    private TencentMeetingService tencentMeetingService;
    @Autowired
    private MeetingInfoService meetingInfoService;
    @Autowired
    private FileProcessProducer producer;
    @Autowired
    private MeetingRecordTemplateService meetingRecordTemplateService;
    @Resource
    private UserIdMapper userIdMapper;
    @Resource
    private CimcService cimcService;

    @Value("${isDev}")
    private Boolean isDev;
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private EmailSender emailSender;


    /**
     * 企微人员定时同步
     */
    @Scheduled(cron = "0 30 6 * * ?")
    public void weComUserSync() {
        ThreadUtil.execute(()-> {
            if (!redisUtils.setnx("weComUserSync", "weComUserSync", 20 * 60 * 60)) {
                return;
            }
            try {
                log.info("-------企微人员定时同步任务开始-------");

                weComService.doUsers();
                log.info("-------企微人员定时同步任务结束--------");
            } catch (Exception e) {
                e.printStackTrace();
                log.error("企微人员定时同步失败");
            } finally {
                redisUtils.del("weComUserSync");
            }
        });
    }

    /**
     * 腾讯会议人员定时同步
     */
    @Scheduled(cron = "0 0 7 * * ?")
    public void TencentUserSync() {
        ThreadUtil.execute(()-> {
            if (!redisUtils.setnx("TencentUserSync", "TencentUserSync", 20 * 60 * 60)) {
                return;
            }
            try {
                log.info("-------腾讯会议人员定时同步任务开始-------");

                tencentMeetingService.doUsers();
                log.info("-------腾讯会议人员定时同步任务结束--------");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                redisUtils.del("TencentUserSync");
            }
        });
    }

    /**
     * 绑定企微和腾会人员关系
     */
    @Scheduled(cron = "0 20 7 * * ?")
    public void userBind() {
        ThreadUtil.execute(()-> {
            if (!redisUtils.setnx("userBind", "userBind", 20 * 60 * 60)) {
                return;
            }
            try {
                log.info("-------关联企微腾会人员定时任务开始-------");
                weComService.userBind();
                log.info("-------关联企微腾会人员定时任务结束--------");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                redisUtils.del("userBind");
            }
        });
    }

    /**
     * 拉取会议并走一遍总流程（生成纪要->推送邮件）
     */
    @Scheduled(fixedRate = 20 * 60 * 1000, initialDelay = 2 * 60 * 1000)
    public void execute() {
        ThreadUtil.execute(()-> {
            if (isDev) {
                return;
            }
            if (!redisUtils.setnx("Scheduled-All", "Scheduled-All", 18 * 60)) {
                return;
            }
            log.info("-------生成纪要定时任务开始-------");
            try {
                //查出企微id和腾会id的关联关系
                List<UserId> userIdRelations = userIdMapper.selectList(null);
//                Map<String, String> widTidRelations = userIdRelations.stream().collect(Collectors.toMap(UserId::getWid, UserId::getTid));
                Map<String, String> tidWidRelations = userIdRelations.stream().collect(Collectors.toMap(UserId::getTid, UserId::getWid));
                //查出企微的人员信息
//                List<WeComUser> weComUserList = weComService.list();
//                Map<String, WeComUser> weComUserMap = weComUserList.stream().collect(Collectors.toMap(WeComUser::getUserId, Function.identity()));

                //智能体授权人员
//                List<UserDTO> accessUserIds = tencentMeetingService.getAccessUserIds(widTidRelations);
//                if (CollectionUtils.isEmpty(accessUserIds)) {
//                    log.info("无生成纪要权限的人员");
//                    return;
//                }
                List<TencentMeetingVO.RecordFile> meetingFiles = tencentMeetingService.getMeetingFiles();

                if (meetingFiles == null || meetingFiles.isEmpty()) {
                    log.info("没有录制文件需要处理");
                    return;
                }

                //获取模板授权的人员
                List<UserDTO.TemplateAuthorizedUserDTO> authorizedUsers = meetingRecordTemplateService.selectAuthorizedUsers();

                // 提交处理任务
                producer.submitBatchTasks(meetingFiles, authorizedUsers, tidWidRelations, Boolean.FALSE);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                redisUtils.del("Scheduled-All");
            }
        });
    }


    /**
     * 定时扫描早于一小时之前的，所有未重试过的会议，重新生成纪要
     */
    @Scheduled(fixedRate = 30 * 60 * 1000, initialDelay = 3 * 60 * 1000)
    public void meetingMinutesRetry() {
        ThreadUtil.execute(()-> {
            if (isDev) {
                return;
            }
            if (!redisUtils.setnx("Scheduled-retry", "Scheduled-retry", 28 * 60)) {
                return;
            }
            try {
                log.info("-------生成纪要重试定时任务开始-------");

                //查出所有早于一小时前的，生成失败且未重试过的会议
                // 不能用status筛选，因为可能线程执行一般服务终止，status状态没变
                List<MeetingInfo> meetingInfoList =
                        meetingInfoService.list(new LambdaQueryWrapper<MeetingInfo>()
                                .isNotNull(MeetingInfo::getMeetingRecordId)
                                .eq(MeetingInfo::getEmailPushAccess, Boolean.TRUE)
                                .eq(MeetingInfo::getEmailGenerateAccess, Boolean.TRUE)
                                .eq(MeetingInfo::getIsGenerated, Boolean.FALSE)
                                .eq(MeetingInfo::getGenerateRetry, Boolean.FALSE)
                                .ne(MeetingInfo::getStatus, MeetingState.EMPTY.getCode())
                                .le(MeetingInfo::getSyncTime, LocalDateTime.now().minusHours(1))
                        );

                if (meetingInfoList == null || meetingInfoList.isEmpty()) {
                    log.info("没有生成失败的会议需要重试");
                    return;
                }
                List<TencentMeetingVO.RecordFile> meetingFiles = new ArrayList<>();
                for (MeetingInfo meetingInfo : meetingInfoList) {
                    TencentMeetingVO.RecordFile recordFile = TencentMeetingVO.RecordFile.builder()
                            .meetingId(meetingInfo.getMeetingId())
                            .meetingRecordId(meetingInfo.getMeetingRecordId())
                            .subMeetingId(meetingInfo.getSubMeetingId())
                            .recordFileIdList(Arrays.asList(meetingInfo.getRecordFileId().split(","))).build();
                    meetingFiles.add(recordFile);
                }

                //查出企微id和腾会id的关联关系
                List<UserId> userIdRelations = userIdMapper.selectList(null);
                Map<String, String> tidWidRelations = userIdRelations.stream().collect(Collectors.toMap(UserId::getTid, UserId::getWid));

                //获取模板授权的人员
                List<UserDTO.TemplateAuthorizedUserDTO> authorizedUsers = meetingRecordTemplateService.selectAuthorizedUsers();

                // 提交处理任务
                producer.submitBatchTasks(meetingFiles, authorizedUsers, tidWidRelations, Boolean.TRUE);
                log.info("-------生成纪要重试定时任务结束--------");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                redisUtils.del("Scheduled-retry");
            }
        });
    }

    /**
     * 定时扫描早于一小时之前的，所有邮件推送未重试过的会议，重新推送邮件
     */
    @Scheduled(fixedRate = 10 * 60 * 1000, initialDelay = 1 * 60 * 1000)
    public void emailPushRetry() {
        ThreadUtil.execute(()-> {
            if (isDev) {
                return;
            }
            if (!redisUtils.setnx("Scheduled-email-retry", "Scheduled-email-retry", 28 * 60)) {
                return;
            }
            try {
                log.info("-------邮件推送重试定时任务开始-------");

                //查出所有早于一小时前的，邮件推送失败且未重试过的会议
                List<MeetingInfo> meetingInfoList =
                        meetingInfoService.list(new LambdaQueryWrapper<MeetingInfo>()
                                .isNotNull(MeetingInfo::getMeetingRecordId)
                                .eq(MeetingInfo::getEmailPushAccess, Boolean.TRUE)
                                .eq(MeetingInfo::getIsGenerated, Boolean.TRUE)
                                .eq(MeetingInfo::getIsPushed, Boolean.FALSE)
                                .eq(MeetingInfo::getPushRetry, Boolean.FALSE)
                                .le(MeetingInfo::getSyncTime, LocalDateTime.now().minusHours(1))
                        );

                if (meetingInfoList == null || meetingInfoList.isEmpty()) {
                    log.info("没有推送失败的邮件需要重试");
                } else {
                    List<TencentMeetingVO.RecordFile> meetingFiles = new ArrayList<>();
                    for (MeetingInfo meetingInfo : meetingInfoList) {
                        TencentMeetingVO.RecordFile recordFile = TencentMeetingVO.RecordFile.builder()
                                .meetingId(meetingInfo.getMeetingId())
                                .subMeetingId(meetingInfo.getSubMeetingId())
                                .meetingRecordId(meetingInfo.getMeetingRecordId())
                                .recordFileIdList(Arrays.asList(meetingInfo.getRecordFileId().split(",")))
                                .build();
                        meetingFiles.add(recordFile);
                    }

                    //查出企微id和腾会id的关联关系
                    List<UserId> userIdRelations = userIdMapper.selectList(null);
                    Map<String, String> tidWidRelations = userIdRelations.stream().collect(Collectors.toMap(UserId::getTid, UserId::getWid));
                    // 提交处理任务
                    producer.submitEmailPushTasks(meetingFiles, tidWidRelations);
                }
                log.info("-------邮件推送重试定时任务结束--------");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                redisUtils.del("Scheduled-email-retry");
            }
        });
    }

    @Resource
    private StatisticsEmailPushProperties statisticsEmailPushProperties;
    @Resource
    private SysUserSyncService sysUserSyncService;

    /**
     * 每天两小时发送会议统计邮件
     */

    @Value(value = "${tencent.base-save-path}")
    private String savePath;
    @Scheduled(cron = "50 59 7,9,11,13,15,17,19,21,23 * * ?")
    public void emailStatisticsPush() {
        ThreadUtil.execute(()->{
            if (isDev) {
                return;
            }
            log.info("推送统计邮件！");
            if (!redisUtils.setnx("emailStatisticsPush", "emailStatisticsPush", 4000)) {
                return;
            }
            log.info("推送统计邮件开始！");
            List<StatisticsEmailPush.Attachment> attachments = new ArrayList<>();

            Date date = new Date();

            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.add(Calendar.HOUR_OF_DAY, 1); // 增加 1 小时
            Date newDate = calendar.getTime(); // 返回增加后的 Date 对象
            String subject = "会议纪要推送记录-" + new SimpleDateFormat("yyyyMMdd HH").format(newDate) + ":00";
            String content;
            if (CollUtil.isEmpty(statisticsEmailPushProperties.getToEmails())) {
                log.error("收件人为空！");
                return;
            }
            File file = new File(savePath + subject + ".xlsx");

            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            try {
                boolean b = meetingInfoService.statisticsEmail(subject, simpleDateFormat1.parse(simpleDateFormat.format(date) + " 00:00:00"),
                        simpleDateFormat1.parse(simpleDateFormat.format(date) + " 23:59:59"), new FileOutputStream(file), DeptCollect.DEPT_MAP);
                if (b) {
                    content = "<p data-olk-copy-source=\\\"MessageBody\\\">Dear all：<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;附件为今天Cmeeting会议纪要生成和发送情况，烦请查收。</p>";
                    StatisticsEmailPush.Attachment attachment = new StatisticsEmailPush.Attachment();
                    attachment.setName(subject);
                    attachment.setBytes(IOUtils.toByteArray(Files.newInputStream(file.toPath())));
                    attachments.add(attachment);
                } else {
                    content = "<p data-olk-copy-source=\\\"MessageBody\\\">Dear all：<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;今天到目前为止没有会议。</p>";
                }
                StatisticsEmailPush emailPushBuilder = StatisticsEmailPush.builder()
                        .toEmails(statisticsEmailPushProperties.getToEmails())
                        .attachments(attachments)
                        .subject(subject)
                        .content(content)
                        .build();
                emailSender.emailStatisticsPush(emailPushBuilder);
            } catch (IOException | ParseException e) {
                throw new RuntimeException(e);
            } finally {
                file.delete();
                redisUtils.del("emailStatisticsPush");
            }
            log.info("推送统计邮件完成！");
        });
    }


    /**
     * 每天6点执行一次
     */
    @Scheduled(cron = "0 0 6 * * ? ")
    public void pullAllDate() {
        ThreadUtil.execute(()-> {
            if (isDev) {
                return;
            }
            log.info("同步用户开始");
            long l = System.currentTimeMillis();
            cimcService.pullCimcData();
            log.info("同步用户结束，耗时: {}ms", System.currentTimeMillis() - l);
        });
    }

    /**
     * 每天0点30分执行一次
     */
    @Scheduled(cron = "00 59 23 * * ?")
    public void deleteDataAfterThan3Months() {
        ThreadUtil.execute(()-> {
            String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
            log.info("删除2天前的数据开始，开始时间: {}", date);
            int count = meetingInfoService.deleteDataAfterThan2Days(date);
            log.info("删除2天前的数据结束，删除数量: {}", count);
        });
    }


//    @Scheduled(cron = "0 0 * * * ?")
    public void errorStatisticsPush() {
        log.info("errorStatisticsPush");
        Date now = new Date();

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(now);
        calendar.add(Calendar.HOUR_OF_DAY, -1);
        Date start = calendar.getTime();

        List<Integer> statusList = new ArrayList<>();
        statusList.add(5);
        statusList.add(6);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<MeetingInfo> meetingInfoList = meetingInfoService.list(new LambdaQueryWrapper<MeetingInfo>()
                .notIn(MeetingInfo::getStatus, statusList)
                .between(MeetingInfo::getSyncTime, sdf.format(start), sdf.format(now))
                .select(MeetingInfo::getStatus)
        );
        if (meetingInfoList.size() == 0) {
            return;
        }
        List<Integer> collect = meetingInfoList.stream().map(MeetingInfo::getStatus).collect(Collectors.toList());

        if (collect.contains(0) || collect.contains(4)) {
            return;
        }
        int sum = collect.size();

        int geneError = 0;
        int pushEmailError = 0;
        for (Integer integer : collect) {
            if (integer == 1){
                geneError++;
            }
            if (integer == 4){
                pushEmailError++;
            }
        }
        if (sum > geneError + pushEmailError) {
            return;
        }
        String subject = "会议纪要推送报警";

        String content = "<p data-olk-copy-source=\\\"MessageBody\\\">Dear all：<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;附件为今天Cmeeting会议纪要生成和发送情况，烦请查收。</p>";
//        List<StatisticsEmailPush.Attachment> attachments = new ArrayList<>();
//        StatisticsEmailPush.Attachment attachment = new StatisticsEmailPush.Attachment();
//        attachment.setName(subject);
//        attachment.setBytes(IOUtils.toByteArray(Files.newInputStream(file.toPath())));
//        attachments.add(attachment);

        StatisticsEmailPush emailPushBuilder = StatisticsEmailPush.builder()
                .toEmails(statisticsEmailPushProperties.getToEmails())
//                .attachments(attachments)
                .subject(subject)
                .content(content)
                .build();
        emailSender.emailStatisticsPush(emailPushBuilder);

    }

}
