package com.usky.iot.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.usky.common.security.utils.SecurityUtils;
import com.usky.iot.domain.PmProject;
import com.usky.iot.domain.PmWorkContent;
import com.usky.iot.domain.PmWorkReport;
import com.usky.iot.mapper.PmProjectMapper;
import com.usky.iot.mapper.PmWorkContentMapper;
import com.usky.iot.mapper.PmWorkReportMapper;
import com.usky.iot.mapper.SysUserMapper;
import com.usky.iot.service.PmProjectService;
import com.usky.iot.service.PmWorkContentService;
import com.usky.common.mybatis.core.AbstractCrudService;
import com.usky.iot.service.vo.ProjectWorkTimeVO;
import com.usky.iot.service.vo.UserWorkTimeVO;
import com.usky.iot.service.vo.WorkHoursStatisticsVO;
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.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 工作内容表 服务实现类
 * </p>
 *
 * @author fu
 * @since 2024-05-20
 */
@Service
public class PmWorkContentServiceImpl extends AbstractCrudService<PmWorkContentMapper, PmWorkContent> implements PmWorkContentService {

    @Autowired
    private PmWorkReportMapper pmWorkReportMapper;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private PmProjectService pmProjectService;

    @Override
    public void deleteContent(Integer reportId) {
        LambdaQueryWrapper<PmWorkContent> deleteWrapper = Wrappers.lambdaQuery();
        deleteWrapper.eq(PmWorkContent::getReportId, reportId);
        baseMapper.delete(deleteWrapper);
    }

    @Override
    public List<PmWorkContent> projectQuery(String startDate, String endDate, String projectName, Integer projectAscription, Integer reportId) {
        if (reportId != null && reportId != 0) {
            LambdaQueryWrapper<PmWorkContent> contentLambdaQuery = Wrappers.lambdaQuery();
            contentLambdaQuery.select(PmWorkContent::getProjectId, PmWorkContent::getProjectName)
                    .eq(PmWorkContent::getReportId, reportId)
                    .groupBy(PmWorkContent::getProjectId, PmWorkContent::getProjectName);
            List<PmWorkContent> pmWorkContentList = this.list(contentLambdaQuery);
            return pmWorkContentList;
        }
        LocalDate start = LocalDate.parse(startDate);
        LocalDate end = LocalDate.parse(endDate);
        String subQueryReports = "SELECT id FROM pm_work_report WHERE report_date BETWEEN '" + start + "' AND '" + end + "' AND tenant_id = " + SecurityUtils.getTenantId();
        String subQueryReport = "SELECT id FROM pm_work_report WHERE FIND_IN_SET('" + SecurityUtils.getUserId() + "', cc_to) > 0 AND tenant_id = " + SecurityUtils.getTenantId();
        String subQueryProjects = "SELECT id FROM pm_project WHERE project_head = '" + SecurityUtils.getUserId() + "' AND tenant_id = " + SecurityUtils.getTenantId();
        LambdaQueryWrapper<PmWorkContent> contentLambdaQuery = Wrappers.lambdaQuery();
        contentLambdaQuery.select(PmWorkContent::getProjectId, PmWorkContent::getProjectName)
                .inSql(PmWorkContent::getReportId, subQueryReports);
        if (StringUtils.isNotBlank(projectName)) {
            contentLambdaQuery.like(PmWorkContent::getProjectName, projectName);
        }
        if (projectAscription == 1) {
            contentLambdaQuery.inSql(PmWorkContent::getProjectId, subQueryProjects);
        } else if (projectAscription == 2) {
            contentLambdaQuery.inSql(PmWorkContent::getReportId, subQueryReport);
        }
        contentLambdaQuery.groupBy(PmWorkContent::getProjectId, PmWorkContent::getProjectName);
        List<PmWorkContent> pmWorkContentList = this.list(contentLambdaQuery);
        return pmWorkContentList;
    }

    @Override
    public List<PmWorkReport> workReportQuery(String startDate, String endDate, String projectName, Integer projectAscription, Integer reportId) {
        List<PmWorkReport> reportList = new ArrayList<>();
        List<PmWorkContent> pmWorkContentList = new ArrayList<>();
        List<Long> userIds = new ArrayList<>();
        if (reportId != null && reportId != 0) {
            LambdaQueryWrapper<PmWorkReport> reportQuery = Wrappers.lambdaQuery();
            reportQuery.select(PmWorkReport::getId, PmWorkReport::getCoordinateWork, PmWorkReport::getTomorrowPlan, PmWorkReport::getCcTo, PmWorkReport::getSubmitterId,
                    PmWorkReport::getCreateTime, PmWorkReport::getReportDate)
                    .eq(PmWorkReport::getId, reportId);
            PmWorkReport report = pmWorkReportMapper.selectOne(reportQuery);
            LambdaQueryWrapper<PmWorkContent> contentQuery = Wrappers.lambdaQuery();
            contentQuery.select(PmWorkContent::getWorkContent, PmWorkContent::getWorkTime, PmWorkContent::getProjectName)
                    .eq(PmWorkContent::getReportId, reportId);
            pmWorkContentList = this.list(contentQuery);
            report.setWorkContents(pmWorkContentList);
            reportList.add(report);
            for (PmWorkReport c : reportList) {
                userIds.add(c.getSubmitterId());
            }
        } else {
            LocalDate start = LocalDate.parse(startDate);
            LocalDate end = LocalDate.parse(endDate);
            String subQueryReports = "SELECT id FROM pm_work_report WHERE report_date BETWEEN '" + start + "' AND '" + end + "' AND tenant_id = " + SecurityUtils.getTenantId();
            String subQueryReport = "SELECT id FROM pm_work_report WHERE FIND_IN_SET('" + SecurityUtils.getUserId() + "', cc_to) > 0 AND tenant_id = " + SecurityUtils.getTenantId();
            String subQueryProjects = "SELECT id FROM pm_project WHERE project_head = '" + SecurityUtils.getUserId() + "' AND tenant_id = " + SecurityUtils.getTenantId();
            String reportIdList = "SELECT report_id FROM pm_work_content WHERE project_name = '" + projectName + "' AND tenant_id = " + SecurityUtils.getTenantId();
            LambdaQueryWrapper<PmWorkContent> contentLambdaQuery = Wrappers.lambdaQuery();
            contentLambdaQuery.select(PmWorkContent::getReportId, PmWorkContent::getWorkContent, PmWorkContent::getWorkTime, PmWorkContent::getProjectName)
                    .inSql(PmWorkContent::getReportId, subQueryReports);
            if (projectAscription == 1) {
                contentLambdaQuery.inSql(PmWorkContent::getProjectId, subQueryProjects);
            } else if (projectAscription == 2) {
                contentLambdaQuery.inSql(PmWorkContent::getReportId, subQueryReport);
            }
            if (StringUtils.isNotBlank(projectName)) {
                contentLambdaQuery.inSql(PmWorkContent::getReportId, reportIdList);
            }
            pmWorkContentList = this.list(contentLambdaQuery);
            if (pmWorkContentList == null || pmWorkContentList.size() == 0) {
                return reportList;
            }
            List<Integer> reportIds = new ArrayList<>();
            for (PmWorkContent a : pmWorkContentList) {
                reportIds.add(a.getReportId());
            }
            LambdaQueryWrapper<PmWorkReport> reportQuery = Wrappers.lambdaQuery();
            reportQuery.select(PmWorkReport::getId, PmWorkReport::getCoordinateWork, PmWorkReport::getTomorrowPlan, PmWorkReport::getCcTo, PmWorkReport::getSubmitterId,
                    PmWorkReport::getCreateTime, PmWorkReport::getReportDate)
                    .in(PmWorkReport::getId, reportIds)
                    .orderByDesc(PmWorkReport::getCreateTime);
            reportList = pmWorkReportMapper.selectList(reportQuery);
            for (PmWorkReport c : reportList) {
                List<PmWorkContent> contents = new ArrayList<>();
                for (PmWorkContent b : pmWorkContentList) {
                    if (b.getReportId() == c.getId()) {
                        contents.add(b);
                    }
                }
                c.setWorkContents(contents);
                userIds.add(c.getSubmitterId());
            }
        }
        LambdaQueryWrapper<SysUser> usersQuery = Wrappers.lambdaQuery();
        usersQuery.select(SysUser::getUserId, SysUser::getNickName)
                .in(SysUser::getUserId, userIds);
        List<SysUser> nickNames = sysUserMapper.selectList(usersQuery);
        for (PmWorkReport d : reportList) {
            for (SysUser e : nickNames) {
                if (e.getUserId().equals(d.getSubmitterId())) {
                    d.setCreateBy(e.getNickName());
                }
            }
        }
        return reportList;
    }

    @Override
    public List<Object> workHourStatistic(Long userId, Integer projectId, Integer filter, String startDate, String endDate, Integer workerOrProject) {
        List<ProjectWorkTimeVO> projectWorkTime = new ArrayList<>();
        List<UserWorkTimeVO> userWorkTimeVO = new ArrayList<>();
        Integer tenantId = SecurityUtils.getTenantId();
        List<Object> returnList = new ArrayList<>();
        LocalDate start = LocalDate.parse(startDate);
        LocalDate end = LocalDate.parse(endDate);
        //找出租户下所有项目
        List<Map<String, Object>> projectIdName = pmProjectService.projectIdName(projectId);
        List<String> pmProjectName = projectIdName.stream()
                .map(map -> (String) map.get("name"))
                .collect(Collectors.toList());
        //所有人员id和nickName
        List<Map<String, Object>> users = pmProjectService.projectUsers(userId);
        List<String> nickName = new ArrayList<>();
        for (Map<String, Object> map : users) {
            Object name = map.get("name");
            nickName.add((String) name);
        }
        //统计userId每个项目所需工时
        List<WorkHoursStatisticsVO> userAndProject = baseMapper.workHoursStatistics(start, end, userId, tenantId);
        Long deptId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
        List<WorkHoursStatisticsVO> userAndProjectD = baseMapper.statisticsDept(start, end, userId, tenantId, deptId);
        if (workerOrProject != 1) {
            returnList.add(nickName);
            //重组返回数据结构
            for (String name : pmProjectName) {
                ProjectWorkTimeVO projectWorkTimeVO = new ProjectWorkTimeVO();
                projectWorkTimeVO.setProjectOrPerson(name);
                List<BigDecimal> workTime = new ArrayList<>();
                boolean hasNonZeroWorkTime = false;
                for (String currentNickName : nickName) {
                    boolean foundWorkTime = false;
                    for (WorkHoursStatisticsVO workHoursStatisticsVO : userAndProject) {
                        String userNickName = workHoursStatisticsVO.getNickName();
                        String projectName = workHoursStatisticsVO.getProjectName();
                        BigDecimal userProjectWorkTime = workHoursStatisticsVO.getWorkTime();
                        if (projectName.equals(name) && userNickName.equals(currentNickName)) {
                            workTime.add(userProjectWorkTime);
                            if (userProjectWorkTime.compareTo(BigDecimal.ZERO) != 0) {
                                hasNonZeroWorkTime = true;
                            }
                            foundWorkTime = true;
                            break;
                        }
                    }
                    if (!foundWorkTime) {
                        workTime.add(BigDecimal.ZERO);
                    }
                }
                if (filter != 2 || hasNonZeroWorkTime) {
                    projectWorkTimeVO.setWorkTime(workTime);
                    projectWorkTime.add(projectWorkTimeVO);
                }
            }
            returnList.add(projectWorkTime);
        } else {
            returnList.add(pmProjectName);
            //重组返回数据结构
            for (String uName : nickName) {
                String name = uName;
                UserWorkTimeVO userWorkTimeVO2 = new UserWorkTimeVO();
                userWorkTimeVO2.setProjectOrPerson(name);
                List<BigDecimal> workTime = new ArrayList<>();
                boolean hasNonZeroWorkTime = false;
                for (String currentNickName : pmProjectName) {
                    boolean foundWorkTime = false;
                    for (WorkHoursStatisticsVO workHoursStatisticsVO : userAndProjectD) {
                        String userNickName = workHoursStatisticsVO.getNickName();
                        String projectName = workHoursStatisticsVO.getProjectName();
                        BigDecimal userProjectWorkTime = workHoursStatisticsVO.getWorkTime();
                        if (userNickName.equals(name) && projectName.equals(currentNickName)) {
                            workTime.add(userProjectWorkTime);
                            if (userProjectWorkTime.compareTo(BigDecimal.ZERO) != 0) {
                                hasNonZeroWorkTime = true;
                            }
                            foundWorkTime = true;
                            break;
                        }
                    }
                    if (!foundWorkTime) {
                        workTime.add(BigDecimal.ZERO);
                    }
                }
                if (filter != 2 || hasNonZeroWorkTime) {
                    userWorkTimeVO2.setWorkTime(workTime);
                    userWorkTimeVO.add(userWorkTimeVO2);
                }
            }
            returnList.add(userWorkTimeVO);
        }
        return returnList;
    }

}
