package com.yuchen.saas.park.service.service.fire.inspect.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yuchen.saas.manage.system.api.entity.NestOrgUser;
import com.yuchen.saas.manage.system.api.feign.IOrgUserClient;
import com.yuchen.saas.park.api.dto.fire.inspect.plan.FireInspectTaskBoardReqDTO;
import com.yuchen.saas.park.api.dto.fire.inspect.plan.FireInspectTaskStatisticsReqDTO;
import com.yuchen.saas.park.api.entity.fire.inspect.SaasParkFireInspectLog;
import com.yuchen.saas.park.api.entity.fire.inspect.SaasParkFireInspectPlan;
import com.yuchen.saas.park.api.entity.fire.inspect.SaasParkFireInspectPlanConfig;
import com.yuchen.saas.park.api.entity.fire.inspect.SaasParkFireInspectPlanTask;
import com.yuchen.saas.park.api.enums.inspect.PlanExecuteStateEnum;
import com.yuchen.saas.park.api.enums.inspect.TaskStateEnum;
import com.yuchen.saas.park.api.vo.fire.inspect.statistics.FireInspectTaskBoardChartVO;
import com.yuchen.saas.park.api.vo.fire.inspect.statistics.FireInspectTaskBoardTodayVO;
import com.yuchen.saas.park.api.vo.fire.inspect.statistics.FireInspectTaskStatisticsVO;
import com.yuchen.saas.park.service.service.fire.inspect.*;
import lombok.RequiredArgsConstructor;
import org.nest.springwrap.core.log.exception.ServiceException;
import org.nest.springwrap.core.mp.base.BaseEntity;
import org.nest.springwrap.core.tool.utils.Func;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhouhanwei
 * @create 2024/9/19 15:07
 */
@Service
@RequiredArgsConstructor
public class SaasParkFireInspectStatisticsServiceImpl implements ISaasParkFireInspectStatisticsService {

    private final ISaasParkFireInspectPlanTaskService inspectPlanTaskService;

    private final ISaasParkFireInspectPlanService inspectPlanService;

    private final IOrgUserClient iOrgUserClient;

    private final ISaasParkFireInspectTypeService inspectTypeService;

    private final ISaasParkFireInspectLogService inspectLogService;

    private final ISaasParkFireInspectPlanConfigService inspectPlanConfigService;

    @Override
    public List<FireInspectTaskStatisticsVO> getInspectTaskStatistics(FireInspectTaskStatisticsReqDTO reqDTO) {
        List<FireInspectTaskStatisticsVO> resultList = new ArrayList<>();
        LambdaQueryWrapper<SaasParkFireInspectPlanTask> lambdaWrapper = Wrappers.lambdaQuery();
        lambdaWrapper.eq(Func.isNotEmpty(reqDTO.getCustomerId()), SaasParkFireInspectPlanTask::getCustomerId, reqDTO.getCustomerId());
        lambdaWrapper.ge(Func.isNotEmpty(reqDTO.getTaskStartDate()), SaasParkFireInspectPlanTask::getTaskDate, reqDTO.getTaskStartDate());
        lambdaWrapper.le(Func.isNotEmpty(reqDTO.getTaskEndDate()), SaasParkFireInspectPlanTask::getTaskDate, reqDTO.getTaskEndDate());
        List<SaasParkFireInspectPlanTask> list = inspectPlanTaskService.list(lambdaWrapper);
        if (Func.isEmpty(list)) {
            return resultList;
        }
        Date newDate = new Date();
        // 根据项目进行分组
        if (reqDTO.getGroupType() == 1) {
            Map<Long, List<SaasParkFireInspectPlanTask>> projectMap = list.stream().collect(Collectors.groupingBy(SaasParkFireInspectPlanTask::getProjectId));
            for (Long projectId : projectMap.keySet()){
                FireInspectTaskStatisticsVO statisticsVO = new FireInspectTaskStatisticsVO();
                statisticsVO.setGroupId(projectId);
                statisticsVO.setGroupType(reqDTO.getGroupType());
                assignTaskStatisticsValue(statisticsVO, projectMap.get(projectId), newDate);
                resultList.add(statisticsVO);
            }
        } else
        // 根据巡检计划进行分组
        if (reqDTO.getGroupType() == 2) {
            Map<Long, List<SaasParkFireInspectPlanTask>> planMap = list.stream().collect(Collectors.groupingBy(SaasParkFireInspectPlanTask::getProjectId));
            List<SaasParkFireInspectPlan> inspectPlanList = inspectPlanService.listByIds(planMap.keySet());
            Map<Long, String> inspectPlanMap = inspectPlanList.stream().collect(Collectors.toMap(BaseEntity::getId, SaasParkFireInspectPlan::getInspectPlanName));
            for (Long projectId : planMap.keySet()){
                FireInspectTaskStatisticsVO statisticsVO = new FireInspectTaskStatisticsVO();
                statisticsVO.setGroupId(projectId);
                statisticsVO.setGroupType(reqDTO.getGroupType());
                // 计划名称
                statisticsVO.setGroupName(inspectPlanMap.get(projectId));
                assignTaskStatisticsValue(statisticsVO, planMap.get(projectId), newDate);
                resultList.add(statisticsVO);
            }
        } else
        // 根据人员进行分组
        if (reqDTO.getGroupType() == 3) {
            Map<String, List<SaasParkFireInspectPlanTask>> inspectPeopleIdsMap = list.stream().collect(Collectors.groupingBy(SaasParkFireInspectPlanTask::getInspectPeopleIds));
            Map<Long, List<SaasParkFireInspectPlanTask>> userIdsMap = new HashMap<>();
            for (String peopleIds : inspectPeopleIdsMap.keySet()){
                List<Long> userIds = Arrays.stream(peopleIds.split(",")).map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
                for (Long userId : userIds) {
                    if (userIdsMap.containsKey(userId)) {
                        userIdsMap.get(userId).addAll(inspectPeopleIdsMap.get(peopleIds));
                    } else {
                        userIdsMap.put(userId, inspectPeopleIdsMap.get(peopleIds));
                    }
                }
            }
            // 获取所有人员数据
            List<NestOrgUser> orgUserList = iOrgUserClient.findOrgUserListByIds((new ArrayList<>(userIdsMap.keySet()))).getData();
            Map<Long, String> orgUserMap = orgUserList.stream().collect(Collectors.toMap(BaseEntity::getId, NestOrgUser::getName));
            // 获取每个人的任务详情
            for (Long userId : userIdsMap.keySet()){
                FireInspectTaskStatisticsVO statisticsVO = new FireInspectTaskStatisticsVO();
                statisticsVO.setGroupId(userId);
                statisticsVO.setGroupType(reqDTO.getGroupType());
                // 计划人员名称
                statisticsVO.setGroupName(orgUserMap.get(userId));
                assignTaskStatisticsValue(statisticsVO, userIdsMap.get(userId), newDate);
                resultList.add(statisticsVO);
            }
        } else
        // 根据巡检类型进行分组
        if (reqDTO.getGroupType() == 4) {
            Map<Long, List<SaasParkFireInspectPlanTask>> inspectTypeIdMap = list.stream().collect(Collectors.groupingBy(SaasParkFireInspectPlanTask::getInspectTypeId));
            Map<Long, String> inspectTypeMap = inspectTypeService.findFireInspectTypeMap(new ArrayList<>(inspectTypeIdMap.keySet()));
            for (Long inspectTypeId : inspectTypeIdMap.keySet()){
                FireInspectTaskStatisticsVO statisticsVO = new FireInspectTaskStatisticsVO();
                statisticsVO.setGroupId(inspectTypeId);
                statisticsVO.setGroupType(reqDTO.getGroupType());
                // 巡检类型 名称
                statisticsVO.setGroupName(inspectTypeMap.get(inspectTypeId));
                assignTaskStatisticsValue(statisticsVO, inspectTypeIdMap.get(inspectTypeId), newDate);
                resultList.add(statisticsVO);
            }
        }
        return resultList;
    }

    private void assignTaskStatisticsValue(FireInspectTaskStatisticsVO statisticsVO, List<SaasParkFireInspectPlanTask> planTaskList, Date newDate) {
        // 巡检计划数
        List<Long> planList = planTaskList.stream()
                .filter(s-> StrUtil.equals(s.getTaskType(), "1")).map(SaasParkFireInspectPlanTask::getPlanId).distinct().collect(Collectors.toList());
        statisticsVO.setInspectPlanNum(planList.size());
        // 巡检任务总数
        statisticsVO.setInspectTaskAllNum(planTaskList.size());
        // 已巡检任务数
        List<SaasParkFireInspectPlanTask> inspectedTaskList = planTaskList.stream()
                .filter(s-> StrUtil.equals(s.getTaskState(), TaskStateEnum.PROCESSED.getCode())).collect(Collectors.toList());
        statisticsVO.setInspectedTaskNum(inspectedTaskList.size());
        // 未巡检任务数
        statisticsVO.setUnInspectTaskNum(planTaskList.size() - inspectedTaskList.size());
        // 逾期未巡检任务数
        long outTimeUnInspectTaskNum = planTaskList.stream().filter(s ->
                PlanExecuteStateEnum.OUT_NO_INSPECT.getCode().equals(s.getExecuteState())).count();
        statisticsVO.setOutTimeUnInspectTaskNum((int) outTimeUnInspectTaskNum);
        // 逾期完成任务数
        long outInspectedTaskNum = planTaskList.stream()
                .filter(s -> s.getTaskProcessedTime().getTime() > s.getTaskEndTime().getTime()
                        && TaskStateEnum.PROCESSED.getCode().equals(s.getTaskState())).count();
        statisticsVO.setOutTimeInspectedTaskNum((int) outInspectedTaskNum);
        // 及时已巡检任务数
        long inTimeInspectedTaskNum = planTaskList.stream()
                .filter(s -> s.getTaskProcessedTime().getTime() <= s.getTaskEndTime().getTime()
                        && TaskStateEnum.PROCESSED.getCode().equals(s.getTaskState())).count();
        statisticsVO.setInTimeInspectedTaskNum((int) inTimeInspectedTaskNum);
        // 正常结果任务数
        long normalInspectTaskNum = planTaskList.stream().filter(s -> "1".equals(s.getInspectResult())).count();
        statisticsVO.setNormalInspectTaskNum((int) normalInspectTaskNum);
        // 异常结果任务数
        long exceptionTaskNum = planTaskList.stream().filter(s -> "2".equals(s.getInspectResult())).count();
        statisticsVO.setAbnormalInspectTaskNum((int) exceptionTaskNum);
        // 已关闭任务数
        long closeInspectTaskNum = planTaskList.stream().filter(s ->
                TaskStateEnum.ClOSE.getCode().equals(s.getTaskState())).count();
        statisticsVO.setCloseInspectTaskNum((int) closeInspectTaskNum);
    }

    @Override
    public FireInspectTaskBoardTodayVO getInspectTaskBoardToday(FireInspectTaskBoardReqDTO reqDTO) {
        FireInspectTaskBoardTodayVO todayVO = new FireInspectTaskBoardTodayVO();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        Date firstDate = calendar.getTime();
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        Date lastDate = calendar.getTime();
        LambdaQueryWrapper<SaasParkFireInspectPlanTask> lambdaWrapper = Wrappers.lambdaQuery();
        lambdaWrapper.eq(Func.isNotEmpty(reqDTO.getCustomerId()), SaasParkFireInspectPlanTask::getCustomerId, reqDTO.getCustomerId());
        lambdaWrapper.eq(Func.isNotEmpty(reqDTO.getProjectId()), SaasParkFireInspectPlanTask::getProjectId, reqDTO.getProjectId());
        lambdaWrapper.ge(SaasParkFireInspectPlanTask::getTaskStartTime, firstDate);
        lambdaWrapper.le(SaasParkFireInspectPlanTask::getTaskStartTime, lastDate);
        List<SaasParkFireInspectPlanTask> taskList = inspectPlanTaskService.list(lambdaWrapper);
        // 今日巡检任务数
        todayVO.setTodayInspectTaskAllNum(taskList.size());
        // 今日已巡检任务数
        List<SaasParkFireInspectPlanTask> inspectedTaskList = taskList.stream()
                .filter(s-> StrUtil.equals(s.getTaskState(), TaskStateEnum.PROCESSED.getCode())).collect(Collectors.toList());
        todayVO.setTodayInspectedTaskNum(inspectedTaskList.size());
        // 今日未巡检任务数
        todayVO.setTodayUnInspectTaskNum(taskList.size() - inspectedTaskList.size());
        // 今日逾期完成任务数
        long outInspectedTaskNum = taskList.stream()
                .filter(s -> s.getTaskProcessedTime().getTime() > s.getTaskEndTime().getTime()
                        && TaskStateEnum.PROCESSED.getCode().equals(s.getTaskState())).count();
        todayVO.setTodayOutTimeInspectedTaskNum((int) outInspectedTaskNum);
        // 及时已巡检任务数
        long InOutInspectTaskNum = taskList.stream()
                .filter(s -> s.getTaskProcessedTime().getTime() <= s.getTaskEndTime().getTime()
                        && TaskStateEnum.PROCESSED.getCode().equals(s.getTaskState())).count();
        todayVO.setTodayInTimeInspectedTaskNum((int) InOutInspectTaskNum);
        // 正常结果任务数
        long normalInspectTaskNum = taskList.stream().filter(s -> "1".equals(s.getInspectResult())).count();
        todayVO.setTodayNormalInspectTaskNum((int) normalInspectTaskNum);
        // 异常结果任务数
        long exceptionTaskNum = taskList.stream().filter(s -> "2".equals(s.getInspectResult())).count();
        todayVO.setTodayAbnormalInspectTaskNum((int) exceptionTaskNum);
        return todayVO;
    }

    @Override
    public FireInspectTaskBoardChartVO getInspectTaskBoardChart(FireInspectTaskBoardReqDTO reqDTO) {
        FireInspectTaskBoardChartVO boardCharVO = new FireInspectTaskBoardChartVO();
        List<SaasParkFireInspectPlanTask> taskList;
        if (StrUtil.equals(reqDTO.getDateFlag(), "年")) {
            taskList = inspectPlanTaskService.getInspectTaskBoardChart(reqDTO);
            if (Func.isNotEmpty(taskList)) {
                Map<String, List<SaasParkFireInspectPlanTask>> yearMap = taskList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getTaskDate(), "yyyy")));
                // 赋值柱状图
                assignTaskBoardChartValue(yearMap, boardCharVO);
            }

        } else
        if (StrUtil.equals(reqDTO.getDateFlag(), "月")) {
            taskList = inspectPlanTaskService.getInspectTaskBoardChart(reqDTO);
            if (Func.isNotEmpty(taskList)) {
                Map<String, List<SaasParkFireInspectPlanTask>> monthMap = taskList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getTaskDate(), "yyyy-MM")));
                // 赋值柱状图
                assignTaskBoardChartValue(monthMap, boardCharVO);
            }
        } else {
            throw new ServiceException("时间维度填入错误");
        }
        // 赋值排行榜
        if (Func.isNotEmpty(taskList)) {
            assignTaskBoardUserRankValue(taskList, boardCharVO);
        }
        return boardCharVO;
    }

    @Override
    public FireInspectTaskBoardChartVO getInspectLogBoardRank(FireInspectTaskBoardReqDTO reqDTO) {
        FireInspectTaskBoardChartVO boardCharVO = new FireInspectTaskBoardChartVO();
        List<SaasParkFireInspectLog> inspectLogList = inspectLogService.getInspectAbnormalLogBoardRank(reqDTO);
        if (Func.isEmpty(inspectLogList)) {
            return boardCharVO;
        }
        Map<Long, List<SaasParkFireInspectLog>> inspectPeopleIdsMap = inspectLogList.stream().collect(Collectors.groupingBy(SaasParkFireInspectLog::getTaskConfigId));
        List<FireInspectTaskBoardChartVO.TaskLogRankDataDTO> taskLogRankDataDTOList = new ArrayList<>();
        // 巡检点名称获取
        List<SaasParkFireInspectPlanConfig> planConfigList = inspectPlanConfigService.listByIds(inspectPeopleIdsMap.keySet());
        Map<Long, String> planConfigMap = planConfigList.stream().collect(Collectors.toMap(BaseEntity::getId, SaasParkFireInspectPlanConfig::getInspectConfigName));
        for (Long taskConfigId : inspectPeopleIdsMap.keySet()) {
            FireInspectTaskBoardChartVO.TaskLogRankDataDTO taskLogRankDataDTO = new FireInspectTaskBoardChartVO.TaskLogRankDataDTO();
            taskLogRankDataDTO.setTaskConfigId(taskConfigId);
            taskLogRankDataDTO.setTaskConfigName(planConfigMap.get(taskConfigId));
            taskLogRankDataDTO.setAbnormalNum(inspectPeopleIdsMap.get(taskConfigId).size());
            taskLogRankDataDTOList.add(taskLogRankDataDTO);
        }
        boardCharVO.setTaskLogRankDataDTOList(taskLogRankDataDTOList);
        return boardCharVO;
    }

    @Override
    public FireInspectTaskBoardChartVO getInspectTypeBoardChart(FireInspectTaskBoardReqDTO reqDTO) {
        FireInspectTaskBoardChartVO boardCharVO = new FireInspectTaskBoardChartVO();
        List<SaasParkFireInspectPlanTask> taskList = inspectPlanTaskService.getInspectTaskBoardChart(reqDTO);
        if (Func.isEmpty(taskList)) {
            return boardCharVO;
        }
        List<FireInspectTaskBoardChartVO.InspectTypeChartDataDTO> inspectTypeChartDataDTOList = new ArrayList<>();
        Map<Long, List<SaasParkFireInspectPlanTask>> inspectTypeIdMap = taskList.stream().collect(Collectors.groupingBy(SaasParkFireInspectPlanTask::getInspectTypeId));
        Map<Long, String> inspectTypeMap = inspectTypeService.findFireInspectTypeMap(new ArrayList<>(inspectTypeIdMap.keySet()));
        for (Long inspectTypeId : inspectTypeIdMap.keySet()) {
            FireInspectTaskBoardChartVO.InspectTypeChartDataDTO inspectTypeChartDataDTO = new FireInspectTaskBoardChartVO.InspectTypeChartDataDTO();
            inspectTypeChartDataDTO.setInspectTypeId(inspectTypeId);
            inspectTypeChartDataDTO.setInspectTypeName(inspectTypeMap.get(inspectTypeId));
            inspectTypeChartDataDTO.setTaskNum(inspectTypeIdMap.get(inspectTypeId).size());
            inspectTypeChartDataDTOList.add(inspectTypeChartDataDTO);
        }
        boardCharVO.setInspectTypeChartDataDTOList(inspectTypeChartDataDTOList);
        return boardCharVO;
    }

    private void assignTaskBoardUserRankValue(List<SaasParkFireInspectPlanTask> taskList, FireInspectTaskBoardChartVO boardCharVO) {
        List<FireInspectTaskBoardChartVO.TaskUserRankDataDTO> taskUserRankDataDTOList = new ArrayList<>();
        Map<String, List<SaasParkFireInspectPlanTask>> inspectPeopleIdsMap = taskList.stream().collect(Collectors.groupingBy(SaasParkFireInspectPlanTask::getInspectPeopleIds));
        Map<Long, List<SaasParkFireInspectPlanTask>> userIdsMap = new HashMap<>();
        for (String peopleIds : inspectPeopleIdsMap.keySet()){
            List<Long> userIds = Arrays.stream(peopleIds.split(",")).map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
            for (Long userId : userIds) {
                if (userIdsMap.containsKey(userId)) {
                    userIdsMap.get(userId).addAll(inspectPeopleIdsMap.get(peopleIds));
                } else {
                    userIdsMap.put(userId, inspectPeopleIdsMap.get(peopleIds));
                }
            }
        }
        // 获取所有人员数据
        List<NestOrgUser> orgUserList = iOrgUserClient.findOrgUserListByIds((new ArrayList<>(userIdsMap.keySet()))).getData();
        Map<Long, String> orgUserMap = orgUserList.stream().collect(Collectors.toMap(BaseEntity::getId, NestOrgUser::getName));
        // 获取每个人的任务详情
        for (Long userId : userIdsMap.keySet()){
            FireInspectTaskBoardChartVO.TaskUserRankDataDTO taskUserRankDataDTO = new FireInspectTaskBoardChartVO.TaskUserRankDataDTO();
            taskUserRankDataDTO.setUserId(userId);
            taskUserRankDataDTO.setUserName(orgUserMap.get(userId));
            taskUserRankDataDTO.setTaskNum(userIdsMap.get(userId).size());
            taskUserRankDataDTOList.add(taskUserRankDataDTO);
        }
        // 排行榜倒序
        boardCharVO.setTaskUserRankDataDTOList(taskUserRankDataDTOList.stream()
                .sorted(Comparator.comparing(FireInspectTaskBoardChartVO.TaskUserRankDataDTO::getTaskNum).reversed()).collect(Collectors.toList()));
    }

    private void assignTaskBoardChartValue(Map<String, List<SaasParkFireInspectPlanTask>> taskMap, FireInspectTaskBoardChartVO boardCharVO) {
        List<FireInspectTaskBoardChartVO.TaskChartDataDTO> taskCharDataDTOList = new ArrayList<>();
        for (String taskDateTime : taskMap.keySet()) {
            FireInspectTaskBoardChartVO.TaskChartDataDTO taskCharDataDTO = new FireInspectTaskBoardChartVO.TaskChartDataDTO();
            // 分组时间
            taskCharDataDTO.setTaskDateTime(taskDateTime);
            // 当前分组任务数
            List<SaasParkFireInspectPlanTask> taskList = taskMap.get(taskDateTime);
            // 逾期未巡检任务数
            long outTimeUnInspectTaskNum = taskList.stream().filter(s ->
                    PlanExecuteStateEnum.OUT_NO_INSPECT.getCode().equals(s.getExecuteState())).count();
            taskCharDataDTO.setOutTimeUnInspectTaskNum((int) outTimeUnInspectTaskNum);
            // 逾期已巡检任务数
            long outTimeInspectedTaskNum = taskList.stream()
                    .filter(s -> s.getTaskProcessedTime().getTime() > s.getTaskEndTime().getTime()
                            && TaskStateEnum.PROCESSED.getCode().equals(s.getTaskState())).count();
            taskCharDataDTO.setOutTimeInspectedTaskNum((int) outTimeInspectedTaskNum);
            // 及时巡检任务数
            long inTimeInspectedTaskNum = taskList.stream()
                    .filter(s -> s.getTaskProcessedTime().getTime() <= s.getTaskEndTime().getTime()
                            && TaskStateEnum.PROCESSED.getCode().equals(s.getTaskState())).count();
            taskCharDataDTO.setInTimeInspectedTaskNum((int) inTimeInspectedTaskNum);
            // 已关闭任务数
            long closeInspectTaskNum = taskList.stream().filter(s ->
                    TaskStateEnum.ClOSE.getCode().equals(s.getTaskState())).count();
            taskCharDataDTO.setCloseInspectTaskNum((int) closeInspectTaskNum);
            taskCharDataDTOList.add(taskCharDataDTO);
        }
        boardCharVO.setTaskChartDataDTOList(taskCharDataDTOList);
    }

}
