package com.ruoyi.ibs.task.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import com.github.pagehelper.Page;
import com.ruoyi.common.core.page.TableDataPageInfo;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.ibs.task.domain.dto.WorkRecordDTO;
import com.ruoyi.ibs.task.domain.entity.AlterConfig;
import com.ruoyi.ibs.task.domain.entity.WorkRecord;
import com.ruoyi.ibs.task.domain.vo.*;
import com.ruoyi.ibs.task.mapper.WorkRecordMapper;
import com.ruoyi.ibs.task.service.WorkRecordService;
import com.ruoyi.system.domain.SysPost;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.ISysPostService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 工作清单记录Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-10-11
 */
@Slf4j
@Service
public class WorkRecordServiceImpl implements WorkRecordService {

    private final static String alterTypesRedisKey = "work:record:alter:types";

    @Autowired
    private WorkRecordMapper workRecordMapper;

    @Autowired
    private ISysPostService sysPostService;

    @Autowired
    private ISysDeptService sysDeptService;

    @Autowired
    private RedisCache redisCache;

    /**
     * 查询我的工作清单
     * 
     * @param workRecordDTO 工作清单记录
     * @return 工作清单记录
     */
    @Override
    public List<WorkRecordVO> getWorkRecordList(WorkRecordDTO workRecordDTO) {
        String username = SecurityUtils.getUsername();
        return workRecordMapper.selectWorkRecordList(workRecordDTO, username);
    }

    /**
     * 查询权限内所有工作清单(仅限管理员)
     * 1、根据当前登录者觉得获取权限内的部门列表
     * 2、查询work_record表里在这些部门列表里的用户
     *
     * @param workRecordDTO 工作清单记录
     * @return 工作清单记录
     */
    @Override
    public TableDataPageInfo<WorkRecordVO> getAllWorkRecordList(WorkRecordDTO workRecordDTO) {
        List<Long> postIds = getPostIdsByRole();
        //开启分页 避开上一个sql
        Page<Object> page = PageUtils.startPage();
        if (SecurityUtils.userRole().equals("manager")){
            List<WorkRecordVO> list = workRecordMapper.selectAllWorkRecordList(workRecordDTO, null, SecurityUtils.getUsername());
            return PageUtils.getDataTable(list, page);
        }else {
            if (postIds.isEmpty()){
                return PageUtils.getDataTable(new ArrayList<>(), page);
            }
            List<WorkRecordVO> list = workRecordMapper.selectAllWorkRecordList(workRecordDTO, postIds, null);
            return PageUtils.getDataTable(list, page);
        }
    }

    /**
     * 修改工作清单记录（只能修改状态和备注）
     * 
     * @param workRecordList 工作清单记录
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchSubmitWorkRecord(List<WorkRecord> workRecordList) {
        if (workRecordList.isEmpty()){
            return 0;
        }
        return workRecordMapper.batchSubmitWorkRecord(workRecordList);
    }

    /**
     * 查询权限内用户工作清单完成情况(仅限管理员)
     *
     * 1、查询当前登录用户权限范围内所有post_ids
     * 2、根据post_ids查询work_record表的所有集合，按照用户分组
     * 3、评估每个用户完成情况
     *
     * @param workRecordDTO 工作清单记录主键
     * @return 工作清单记录
     */
    @Override
    public TableDataPageInfo<WorkCompleteVO> getCompleteStatus(WorkRecordDTO workRecordDTO) {
        List<Long> postIds = getPostIdsByRole();
        //开启分页 避开上一个sql
        Page<Object> page = PageUtils.startPage();
        if (postIds.isEmpty()){
            return PageUtils.getDataTable(new ArrayList<>(), page);
        }
        List<WorkCompleteVO> voList= workRecordMapper.selectCompleteStatus(workRecordDTO, postIds);
        //计算排名
        int rankNum = (page.getPageNum() - 1) * page.getPageSize() + 1;
        if (voList != null && !voList.isEmpty()){
            IntStream.range(0, voList.size()).forEach(i -> voList.get(i).setRankNum(rankNum + i));
        }
        return PageUtils.getDataTable(voList, page);
    }

    /**
     * 获取我的预警信息
     *
     * @param alterType 预警类型
     * @return 预警信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<AlterVO> getAlterList(String status, String alterType) {
        String username = SecurityUtils.getUsername();
        return workRecordMapper.selectAlterList(username, status, alterType);
    }

    /**
     * 获取权限内所有预警信息(仅限管理员)
     *
     * 1、根据登录者角色查询权限内部门ids
     * 2、根据部门ids查询work_record表里所有该部门下的所有用户对应的预警信息
     *
     * @param alterType 预警类型
     * @return 预警信息
     */
    @Override
    public List<AlterVO> getAllAlterList(String status, String alterType) {
        List<AlterVO> alterVOS = workRecordMapper.selectAllAlterList(String.valueOf(SecurityUtils.getDeptId()), SecurityUtils.userRole(), status, alterType, SecurityUtils.getUsername());
        // 将 userName 和 nickName 以 "userName-nickName" 的方式拼接后设置到 custInfo 字段
        if (alterVOS != null && !alterVOS.isEmpty()) {
            alterVOS.forEach(alterVO -> {
                String userName = alterVO.getUserName();
                String nickName = alterVO.getNickName();
                if (userName != null && nickName != null) {
                    alterVO.setUserInfo(nickName + "-" + userName);
                } else if (userName != null) {
                    alterVO.setUserInfo(userName);
                } else if (nickName != null) {
                    alterVO.setUserInfo(nickName);
                } else {
                    alterVO.setUserInfo("");
                }
            });
        }
        return alterVOS;
    }

    /**
     * 定时任务生成工作清单
     *
     * 1、根据频率类型计算时间范围
     * 2、查询模板表里当前频率类型处于启用状态下的工作清单（联表查用户信息等）
     * 3、插入工作清单记录表
     *
     * @param frequencyType 频率类型
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int generateWorkRecordScheduled(String frequencyType) {
        log.info("=====开始执行生成工作清单定时任务=====,频率类型为: " + frequencyType);
        //计算时间范围
        LocalDate today = LocalDate.now();
        Date startTime = calculateStartTime(frequencyType, today);
        Date endTime = calculateEndTime(frequencyType, today);
        log.info("时间范围: {} 至 {}", startTime, endTime);
        List<WorkRecord> recordsToGenerate = workRecordMapper.selectRecordsToGenerate(frequencyType, startTime, endTime);
        if (recordsToGenerate.isEmpty()){
            log.info("没有需要生成的记录");
            return 0;
        }
        log.info("需要生成的记录数量: {}", recordsToGenerate.size());
        int insertCount = workRecordMapper.batchInsertWorkRecord(recordsToGenerate);
        log.info("=====生成工作清单定时任务执行成功=====, 生成工作清单记录数量: {}", insertCount);
        return insertCount;
    }

    /**
     * 定时判断工作清单是否逾期，每日凌晨一点判断一次
     *
     * 1、获取当前时间
     * 2、查询表里当前时间在start_time和end_time之间，并且is_overdue为0的记录，修改is_overdue为1
     *
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int setOverdue(){
        //获取当前时间
        LocalDateTime now = LocalDateTime.now();
        log.info("=====开始执行设置逾期工作清单定时任务=====,当前时间为: " + now);
        //查询工作清单记录
        return workRecordMapper.updateOverdueRecord(now);
    }

    /**
     * 获取预警配置信息
     * @return
     */
    @Override
    public List<AlterConfigVO> getAlterConfigList(String alterType){
        return workRecordMapper.selectAlterConfigList(alterType);
    }

    @Override
    public int updateAlterConfig(AlterConfig alterConfig){
        alterConfig.setUpdateBy(SecurityUtils.getUsername());
        alterConfig.setUpdateTime(new Date());
        return workRecordMapper.updateAlterConfig(alterConfig);
    }

    @Override
    public int updateReadTime(Long id) {
        return workRecordMapper.updateReadTime(id, SecurityUtils.getUsername());
    }

    @Override
    public AlterCountVO getAlterCount(Date reportTime) {
        AlterCountVO alterCountVO = workRecordMapper.selectAlterCount(reportTime, SecurityUtils.userRole(), String.valueOf(SecurityUtils.getDeptId()));
        // 计算完成率
        if (alterCountVO.getAlterCount() > 0) {
            BigDecimal completeRate = BigDecimal.valueOf(alterCountVO.getCompleteCount())
                    .multiply(BigDecimal.valueOf(100))
                    .divide(BigDecimal.valueOf(alterCountVO.getAlterCount()), 2, RoundingMode.HALF_UP);
            alterCountVO.setCompleteRate(completeRate);
        } else {
            alterCountVO.setCompleteRate(BigDecimal.ZERO);
        }
        return alterCountVO;
    }

    @Override
    public List<String> getAlterTypes() {
        String headId = SecurityUtils.getHeadId();
        String cacheKey = alterTypesRedisKey + ":" + headId;
        List<String> cachedTypes = redisCache.getCacheObject(cacheKey);
        if (cachedTypes != null) {
            return cachedTypes;
        }
        List<String> types = workRecordMapper.selectAlterTypes(headId);
        redisCache.setCacheObjectToEndDay(cacheKey, types);
        return types;
    }

    /**
     * 获取当前登录用户权限范围内所有post_ids
     * @return
     */
    private List<Long> getPostIdsByRole(){
        List<SysPost> sysPosts = sysPostService.selectPostList(new SysPost());
        if (sysPosts == null || sysPosts.isEmpty()){
            return new ArrayList<>();
        }
        return sysPosts.stream()
                .map(SysPost::getPostId)
                .collect(Collectors.toList());
    }

    /**
     * 计算工作清单开始时间
     * @param frequencyType
     * @param date
     * @return
     */
    private Date calculateStartTime(String frequencyType, LocalDate date){
        LocalDateTime startTime;
        switch (frequencyType){
            case "0":
                startTime = LocalDateTime.of(date, LocalTime.MIN);
                break;
            case "1":
                startTime= LocalDateTime.of(date.with(DayOfWeek.MONDAY), LocalTime.MIN);
                break;
            case "2":
                startTime = LocalDateTime.of(date.with(TemporalAdjusters.firstDayOfMonth()), LocalTime.MIN);
                break;
            case "3":
                int quarter = (date.getMonthValue() - 1) / 3;
                int firstMonthOfQuarter = quarter * 3 + 1;
                startTime = LocalDateTime.of(LocalDate.of(date.getYear(), firstMonthOfQuarter,1), LocalTime.MIN);
                break;
            case "4":
                startTime = LocalDateTime.of(LocalDate.of(date.getYear(), 1, 1), LocalTime.MIN);
                break;
            default:
                throw new IllegalArgumentException("不支持的频率类型: " + frequencyType);
        }
        return java.sql.Timestamp.valueOf(startTime);
    }

    /**
     * 计算工作清单结束时间
     * @param frequencyType
     * @param date
     * @return
     */
    private Date calculateEndTime(String frequencyType, LocalDate date){
        LocalDateTime endTime;
        switch (frequencyType){
            case "0":
                endTime = LocalDateTime.of(date, LocalTime.MAX);
                break;
            case "1":
                endTime = LocalDateTime.of(date.with(DayOfWeek.SUNDAY), LocalTime.MAX);
                break;
            case "2":
                endTime = LocalDateTime.of(date.with(TemporalAdjusters.lastDayOfMonth()), LocalTime.MAX);
                break;
            case "3":
                int quarter = (date.getMonthValue() - 1) / 3;
                int lastMonthOfQuarter = quarter * 3 + 3;
                LocalDate lastDayOfQuarter = LocalDate.of(date.getYear(), lastMonthOfQuarter, 1).with(TemporalAdjusters.lastDayOfMonth());
                endTime = LocalDateTime.of(lastDayOfQuarter, LocalTime.MAX);
                break;
            case "4":
                endTime= LocalDateTime.of(LocalDate.of(date.getYear(), 12, 31), LocalTime.MAX);
                break;
            default:
                throw new IllegalArgumentException("不支持的频率类型: " + frequencyType);
        }
        return java.sql.Timestamp.valueOf(endTime);
    }

}
