package com.usky.iot.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.usky.common.core.bean.CommonPage;
import com.usky.common.core.exception.BusinessException;
import com.usky.common.security.utils.SecurityUtils;
import com.usky.iot.domain.PmReceive;
import com.usky.iot.domain.PmTimeConf;
import com.usky.iot.domain.PmWorkContent;
import com.usky.iot.domain.PmWorkReport;
import com.usky.iot.mapper.*;
import com.usky.iot.service.PmTimeConfService;
import com.usky.common.mybatis.core.AbstractCrudService;
import com.usky.iot.service.vo.PmReportReadersVO;
import com.usky.iot.service.vo.PmSubmitCountResponseVO;
import com.usky.system.domain.SysUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 工作报告提交时间配置表 服务实现类
 * </p>
 *
 * @author fu
 * @since 2025-01-10
 */
@Service
public class PmTimeConfServiceImpl extends AbstractCrudService<PmTimeConfMapper, PmTimeConf> implements PmTimeConfService {

    @Autowired
    private PmTimeConfMapper pmTimeConfMapper;

    @Autowired
    private PmWorkReportMapper pmWorkReportMapper;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private PmWorkContentMapper pmWorkContentMapper;

    @Autowired
    private PmReceiveMapper pmReceiveMapper;

    // 统计工作报提交
    @Override
    public PmSubmitCountResponseVO submitCount(String submitDate) {
        Integer tenantId = SecurityUtils.getTenantId();
        PmSubmitCountResponseVO responseVO = new PmSubmitCountResponseVO();
        LocalDate countDate = null;
        try {
            countDate = LocalDate.parse(submitDate);
        } catch (Exception e) {
            throw new BusinessException("提交日期有误" + e.getMessage());
        }

        // 查询时间配置
        PmTimeConf timeConf = getTimeConf(tenantId);
        if (timeConf == null) {
            throw new BusinessException("未找到工作报提交统计告时间配置，请联系管理员");
        } else if (countDate.equals(LocalDate.now()) && timeConf.getStartTime().isAfter(LocalTime.now()) || countDate.isAfter(LocalDate.now())) {
            responseVO.setSubmitOnTime(0);
            responseVO.setSubmitLate(0);
            responseVO.setNotSubmitted(0);
            responseVO.setStatisticalDate(countDate);
            return responseVO;
        }

        LocalTime startTime = timeConf.getStartTime();
        LocalTime onTime = timeConf.getOnTime();
        LocalTime endTime = timeConf.getEndTime();
        LocalDateTime startDateTime = LocalDateTime.of(countDate, startTime);
        LocalDateTime onDateTime = LocalDateTime.of(countDate, onTime);
        LocalDateTime endDateTime = LocalDateTime.of(countDate, endTime).plusDays(1);

        // 按时提交
        List<PmWorkReport> pmWorkReports = reportList(tenantId, 0, startDateTime, onDateTime, endDateTime);
        Integer submitOnTime = pmWorkReports.size();

        // 延迟提交
        List<PmWorkReport> pmWorkReports2 = reportList(tenantId, 1, startDateTime, onDateTime, endDateTime);
        Integer submitLate = pmWorkReports2.size();

        Integer suerSum = users(tenantId).size();
        // 未提交
        Integer notSubmitted = suerSum - submitOnTime - submitLate;

        responseVO.setSubmitOnTime(submitOnTime);
        responseVO.setSubmitLate(submitLate);
        responseVO.setNotSubmitted(notSubmitted);
        responseVO.setStatisticalDate(countDate);
        return responseVO;
    }

    @Override
    public CommonPage<Object> submitPage(String submitDate, Integer queryType, Integer reportId, Integer pageNum, Integer pageSize) {
        Integer tenantId = SecurityUtils.getTenantId();
        Long userId2 = SecurityUtils.getUserId();
        LocalDate countDate = null;
        try {
            countDate = LocalDate.parse(submitDate);
        } catch (Exception e) {
            throw new BusinessException("提交日期有误" + e.getMessage());
        }

        List<SysUser> userList = users(tenantId);

        PmTimeConf timeConf = getTimeConf(tenantId);
        if (timeConf == null) {
            throw new BusinessException("未找到工作报提交统计告时间配置，请联系管理员");
        }
        if ((LocalDate.now().equals(countDate) && timeConf.getStartTime().isAfter(LocalTime.now())) ||
                countDate.isAfter(LocalDate.now())) {
            return new CommonPage<>();
        }

        LocalTime startTime = timeConf.getStartTime();
        LocalTime onTime = timeConf.getOnTime();
        LocalTime endTime = timeConf.getEndTime();
        LocalDateTime startDateTime = LocalDateTime.of(countDate, startTime);
        LocalDateTime onDateTime = LocalDateTime.of(countDate, onTime);
        LocalDateTime endDateTime = LocalDateTime.of(countDate, endTime).plusDays(1);

        LambdaQueryWrapper<PmWorkReport> reportQuery = Wrappers.lambdaQuery();
        reportQuery.eq(PmWorkReport::getTenantId, tenantId).eq(PmWorkReport::getReportStatus, 1);

        if (reportId != null && reportId != 0) {
            reportQuery.eq(PmWorkReport::getId, reportId);
        } else {
            switch (queryType) {
                // 按时提交
                case 0:
                    reportQuery.between(PmWorkReport::getSubmitDate, startDateTime, onDateTime);
                    break;
                // 延迟提交
                case 1:
                    reportQuery.between(PmWorkReport::getSubmitDate, onDateTime, endDateTime);
                    break;
                // 未提交
                case 2:
                    List<Long> userId = new ArrayList<>();
                    // 按时提交
                    List<PmWorkReport> pmWorkReports = reportList(tenantId, 0, startDateTime, onDateTime, endDateTime);
                    pmWorkReports.forEach(report -> {
                        userId.add(report.getSubmitterId());
                    });
                    // 延迟提交
                    List<PmWorkReport> pmWorkReports2 = reportList(tenantId, 1, startDateTime, onDateTime, endDateTime);
                    pmWorkReports2.forEach(report -> {
                        userId.add(report.getSubmitterId());
                    });
                    // 未提交
                    List<SysUser> unSubmitted = userList.stream().filter(user -> !userId.contains(user.getUserId())).collect(Collectors.toList());

                    int total = unSubmitted.size();
                    int start = (pageNum - 1) * pageSize;
                    int end = Math.min(start + pageSize, total);

                    List<SysUser> pageData;
                    if (start < total) {
                        pageData = unSubmitted.subList(start, end);
                    } else {
                        pageData = Collections.emptyList();
                    }
                    return new CommonPage<>(Collections.singletonList(pageData), total, pageSize, pageNum);

                default:
                    throw new BusinessException("报告统计分页参数错误！");
            }
            if (countDate.equals(LocalDate.now()) && timeConf.getStartTime().isAfter(LocalTime.now())) {
                return new CommonPage<>();
            }
            reportQuery.eq(PmWorkReport::getReportDate, countDate);
        }

        List<PmWorkReport> pmWorkReports = pmWorkReportMapper.selectList(reportQuery);
        if (pmWorkReports.isEmpty()) {
            return new CommonPage<>();
        }
        List<Integer> reportIds = new ArrayList<>();
        pmWorkReports.forEach(report -> {
            reportIds.add(report.getId());
        });

        LambdaQueryWrapper<PmWorkContent> reportContents = Wrappers.lambdaQuery();
        reportContents.in(PmWorkContent::getReportId, reportIds);
        List<PmWorkContent> pmWorkContentList = pmWorkContentMapper.selectList(reportContents);

        // 查询已读状态
        LambdaQueryWrapper<PmReceive> statusQuery = Wrappers.lambdaQuery();
        statusQuery.select(PmReceive::getReportId, PmReceive::getReadFlag).eq(PmReceive::getReceiverId, userId2);
        if (reportId != null && reportId != 0) {
            statusQuery.eq(PmReceive::getReportId, reportId);
        } else {
            statusQuery.in(PmReceive::getReportId, reportIds);
        }
        List<PmReceive> receiveList2 = pmReceiveMapper.selectList(statusQuery);

        Map<Integer, Integer> reportReadFlags = new HashMap<>();
        for (PmReceive pmReceive : receiveList2) {
            Integer reportId2 = pmReceive.getReportId();
            reportReadFlags.put(reportId2, pmReceive.getReadFlag());
        }

        List<Long> userIds = new ArrayList<>();

        // 已读未读数量查询
        List<PmReceive> receives = new ArrayList<>();
        receives = receives(reportIds);
        Map<Integer, List<PmReceive>> reportReceivesMap = new HashMap<>();
        reportReceivesMap = receives.stream().collect(Collectors.groupingBy(PmReceive::getReportId));
        for (PmWorkReport report : pmWorkReports) {
            List<PmWorkContent> contents = pmWorkContentList.stream().filter(content -> content.getReportId().equals(report.getId())).collect(Collectors.toList());
            report.setWorkContents(contents);
            userIds.add(report.getSubmitterId());

            Integer readFlagValue = reportReadFlags.get(report.getId());
            report.setReadFlag(readFlagValue);

            // 创建人名字替换
            if (!userIds.isEmpty()) {
                List<SysUser> nickNames = nickNames(userIds);
                Map<Long, String> userNicknameMap = nickNames.stream().collect(Collectors.toMap(SysUser::getUserId, SysUser::getNickName));
                report.setCreateBy(userNicknameMap.get(report.getSubmitterId()));
            }

            List<Long> readAlready = new ArrayList<>();
            List<Long> readNotAlready = new ArrayList<>();
            int readCount = 0;
            int unreadCount = 0;
            if (!reportReceivesMap.isEmpty()) {
                List<PmReceive> reportReceives = reportReceivesMap.getOrDefault(report.getId(), Collections.emptyList());
                for (PmReceive pmReceive : reportReceives) {
                    if (pmReceive.getReadFlag() == 1) {
                        readCount++;
                        readAlready.add(pmReceive.getReceiverId());
                    } else {
                        unreadCount++;
                        readNotAlready.add(pmReceive.getReceiverId());
                    }
                }
            }

            PmReportReadersVO readUnreadVO = new PmReportReadersVO(readAlready, readNotAlready, readCount, unreadCount);
            report.setPmReportReaders(readUnreadVO);

            // 头像
            for (SysUser sysUser : userList) {
                if (sysUser.getUserId().equals(report.getSubmitterId())) {
                    report.setAvatar(sysUser.getAvatar());
                    break;
                }
            }
        }

        int total = pmWorkReports.size();
        int start = (pageNum - 1) * pageSize;
        int end = Math.min(start + pageSize, total);

        List<PmWorkReport> pageData;
        if (start < total) {
            pageData = pmWorkReports.subList(start, end);
        } else {
            pageData = Collections.emptyList();
        }

        return new CommonPage<>(Collections.singletonList(pageData), total, pageSize, pageNum);
    }

    // 查询已读未读
    private List<PmReceive> receives(List<Integer> reports) {
        LambdaQueryWrapper<PmReceive> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.select(PmReceive::getReportId, PmReceive::getReadFlag, PmReceive::getReceiverId).in(PmReceive::getReportId, reports);
        return pmReceiveMapper.selectList(queryWrapper);
    }

    // 构建查询条件，返回按时提交和延迟提交列表
    private List<PmWorkReport> reportList(Integer tenantId, Integer queryType, LocalDateTime startDateTime, LocalDateTime onDateTime, LocalDateTime endDateTime) {

        LocalDate countDate = startDateTime.toLocalDate();

        LambdaQueryWrapper<PmWorkReport> reportQuery = new LambdaQueryWrapper<>();
        reportQuery.eq(PmWorkReport::getTenantId, tenantId)
                .eq(PmWorkReport::getReportDate, countDate)
                .eq(PmWorkReport::getReportStatus, 1);
        switch (queryType) {
            // 按时提交
            case 0:
                reportQuery.between(PmWorkReport::getSubmitDate, startDateTime, onDateTime);
                break;
            // 延迟提交
            case 1:
                reportQuery.between(PmWorkReport::getSubmitDate, onDateTime, endDateTime);
                break;
        }
        return pmWorkReportMapper.selectList(reportQuery);
    }

    // 获取报告时间配置
    @Override
    public PmTimeConf getTimeConf(Integer tenantId) {
        LambdaQueryWrapper<PmTimeConf> timeConfQuery = new LambdaQueryWrapper<>();
        timeConfQuery.eq(PmTimeConf::getTenantId, tenantId)
                .eq(PmTimeConf::getConfType, "PM");
        return pmTimeConfMapper.selectOne(timeConfQuery);
    }

    @Override
    public void addOrUpdateTimeConf(PmTimeConf pmTimeConf) {
        String username = SecurityUtils.getUsername();
        Long deptId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
        LocalDateTime now = LocalDateTime.now();
        if (pmTimeConf.getId() == null) {
            Integer tenantId = SecurityUtils.getTenantId();
            verificationTimeConf(pmTimeConf);
            pmTimeConf.setTenantId(tenantId);
            pmTimeConf.setCreateBy(username);
            pmTimeConf.setCreateTime(now);
            pmTimeConf.setDeptId(deptId);
            pmTimeConfMapper.insert(pmTimeConf);
        } else {
            verificationTimeConf(pmTimeConf);
            pmTimeConf.setUpdateBy(username);
            pmTimeConf.setUpdateTime(now);
            pmTimeConfMapper.updateById(pmTimeConf);
        }
    }

    @Override
    public void isOpen(Integer isOpen, Integer id) {
        Long userId = SecurityUtils.getUserId();
        String username = SecurityUtils.getUsername();
        LocalDateTime now = LocalDateTime.now();
        PmTimeConf pmTimeConf = pmTimeConfMapper.selectById(id);
        if (pmTimeConf == null){
            throw new BusinessException("配置不存在！联系管理员后重试");
        }

        if (isOpen == 1) {
            pmTimeConf.setNotifier(pmTimeConf.getNotifier() + "," + userId);
        } else if (isOpen == 0) {
            pmTimeConf.setNotifier(pmTimeConf.getNotifier().replace("," + userId, ""));
        } else {
            throw new BusinessException("参数异常，报告提醒开关操作失败！");
        }

        pmTimeConf.setUpdateBy(username);
        pmTimeConf.setUpdateTime(now);
        pmTimeConfMapper.updateById(pmTimeConf);
    }

    private void verificationTimeConf(PmTimeConf pmTimeConf) {
        if (StringUtils.isBlank(pmTimeConf.getConfName())) {
            throw new BusinessException("配置名称不能为空！");
        } else if (pmTimeConf.getConfName().length() > 64) {
            throw new BusinessException("配置名称长度不能超过64个字符！");
        }

        if (StringUtils.isBlank(pmTimeConf.getConfType())) {
            throw new BusinessException("配置类型不能为空！");
        } else if (pmTimeConf.getConfType().length() > 64) {
            throw new BusinessException("配置类型长度不能超过64个字符！");
        }

        if (pmTimeConf.getStartTime() == null) {
            throw new BusinessException("开始时间不能为空！");
        } else if (pmTimeConf.getStartTime().isAfter(pmTimeConf.getEndTime())) {
            throw new BusinessException("开始时间不能大于结束时间！");
        }

        if (pmTimeConf.getEndTime() == null) {
            throw new BusinessException("结束时间不能为空！");
        } else if (pmTimeConf.getEndTime().isBefore(pmTimeConf.getStartTime())) {
            throw new BusinessException("结束时间不能小于开始时间！");
        }

        if (pmTimeConf.getOnTime() == null) {
            throw new BusinessException("准时时间不能为空！");
        } else if (pmTimeConf.getOnTime().isBefore(pmTimeConf.getStartTime()) || pmTimeConf.getOnTime().isAfter(pmTimeConf.getEndTime())) {
            throw new BusinessException("准时时间必须在开始时间和结束时间之间！");
        }
    }

    // 查询用户信息
    private List<SysUser> users(Integer tenantId) {
        LambdaQueryWrapper<SysUser> userQuery = new LambdaQueryWrapper<>();
        userQuery.select(SysUser::getUserId, SysUser::getDeptId, SysUser::getUserName, SysUser::getNickName, SysUser::getPhonenumber,
                        SysUser::getAvatar, SysUser::getSex, SysUser::getAddress, SysUser::getEmail)
                .eq(SysUser::getTenantId, tenantId)
                .eq(SysUser::getStatus, 0)
                .eq(SysUser::getDelFlag, 0)
                .eq(SysUser::getUserType, "00");
        return sysUserMapper.selectList(userQuery);
    }

    // 获取用户昵称
    private List<SysUser> nickNames(List<Long> userIds) {
        LambdaQueryWrapper<SysUser> userQuery = new LambdaQueryWrapper<>();
        userQuery.select(SysUser::getUserId, SysUser::getNickName)
                .in(SysUser::getUserId, userIds);
        return sysUserMapper.selectList(userQuery);
    }

}
