package com.microservices.pms.specialArea.service;

import com.microservices.common.core.web.controller.BaseController;
import com.microservices.pms.specialArea.domain.ForgeProject;
import com.microservices.pms.specialArea.domain.ZonePmsProject;
import com.microservices.pms.specialArea.domain.vo.KeyValVO;
import com.microservices.pms.specialArea.domain.vo.ProjectSituationVO;
import com.microservices.pms.specialArea.mapper.SoftwareFactStatisForgeMapper;
import com.microservices.pms.specialArea.mapper.SoftwareFactStatisPmsMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

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

import static com.microservices.pms.specialArea.constant.Constant.*;

@Service
@RequiredArgsConstructor
public class SoftwareFactStatisticsServiceImpl extends BaseController {

    private final SoftwareFactStatisPmsMapper statisPmsMapper;
    private final SoftwareFactStatisForgeMapper statisForgeMapper;

    public static Date[] getDayStartAndEnd(int days) {
        // 获取今天的日期
        LocalDate today = LocalDate.now();
        today = today.plusDays(days);
        // 获取今天的开始时间（00:00:00）
        LocalDateTime startOfDay = today.atStartOfDay();

        // 获取今天的结束时间（23:59:59.999999999）
        LocalDateTime endOfDay = today.atTime(LocalTime.MAX);

        // 转换为 Date 对象
        Date startDate = Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant());
        Date endDate = Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());

        return new Date[]{startDate, endDate};
    }

    public static Date[] getCurrentWeek() {
        LocalDate today = LocalDate.now();
        LocalDate startOfWeek = today.with(java.time.DayOfWeek.MONDAY);
        LocalDate endOfWeek = today.with(java.time.DayOfWeek.SUNDAY);

        LocalDateTime startDateTime = startOfWeek.atStartOfDay();
        LocalDateTime endDateTime = endOfWeek.atTime(23, 59, 59);

        return new Date[]{
                Date.from(startDateTime.atZone(ZoneId.systemDefault()).toInstant()),
                Date.from(endDateTime.atZone(ZoneId.systemDefault()).toInstant())
        };
    }

    public static Date[] getCurrentMonth() {
        LocalDate today = LocalDate.now();
        LocalDate startOfMonth = today.withDayOfMonth(1);
        LocalDate endOfMonth = today.withDayOfMonth(today.lengthOfMonth());

        LocalDateTime startDateTime = startOfMonth.atStartOfDay();
        LocalDateTime endDateTime = endOfMonth.atTime(23, 59, 59);

        return new Date[]{
                Date.from(startDateTime.atZone(ZoneId.systemDefault()).toInstant()),
                Date.from(endDateTime.atZone(ZoneId.systemDefault()).toInstant())
        };
    }

    public Map<String, Object> todayWorkSituation() {

        Map<String, Object> res = new HashMap<>();

        ForgeProject forgeProject = new ForgeProject();
        forgeProject.setStatusIds(ISSUE_NOT_FINISHED);

        //需求待评审
        forgeProject.setPmIssueType(NEED);
        Long needNotFinishCount = statisForgeMapper.countForgeProject(forgeProject);
        res.put("needNotFinishCount", needNotFinishCount);

        //任务待完成
        forgeProject.setPmIssueType(TASK);
        Long taskNotFinishCount = statisForgeMapper.countForgeProject(forgeProject);
        res.put("taskNotFinishCount", taskNotFinishCount);

        //缺陷待修复
        forgeProject.setPmIssueType(BUG);
        Long bugNotFinishCount = statisForgeMapper.countForgeProject(forgeProject);
        res.put("bugNotFinishCount", bugNotFinishCount);
        //测试用例未执行数
        forgeProject.setStatusIds(Collections.singletonList(TASK_CASE_STATUS_NOT_EXEC));
        Long notExecTestCaseCount = statisPmsMapper.countTestCaseInSheet(forgeProject);
        res.put("notExecTestCaseCount", notExecTestCaseCount);

        ForgeProject f2 = new ForgeProject();
        f2.setStatusIds(ISSUE_NOT_FINISHED);
        f2.setPmIssueType(TASK);
        //任务最多项目
        Long taskMaxProjectId = statisForgeMapper.countForgeProjectByProject(f2);
        ZonePmsProject taskMaxProject = statisPmsMapper.selectPmsProjectById(taskMaxProjectId);
        res.put("taskMaxProject", taskMaxProject == null ?"": taskMaxProject.getProjectName());
        //任务最多个人
        Long taskMaxAssignerId = statisForgeMapper.countForgeProjectByAssigner(f2);
        String taskMaxAssigner = statisPmsMapper.selectPmsUserByGitlinkId(taskMaxAssignerId);
        res.put("taskMaxAssigner", taskMaxAssigner);
        f2.setPmIssueType(BUG);
        //缺陷最多项目
        Long bugMaxProjectId = statisForgeMapper.countForgeProjectByProject(f2);
        ZonePmsProject bugMaxProject = statisPmsMapper.selectPmsProjectById(bugMaxProjectId);
        res.put("bugMaxProject", bugMaxProject == null ?"":  bugMaxProject.getProjectName());
        //缺陷最多个人
        Long bugMaxAssignerId = statisForgeMapper.countForgeProjectByAssigner(f2);
        String bugMaxAssigner = statisPmsMapper.selectPmsUserByGitlinkId(bugMaxAssignerId);
        res.put("bugMaxAssigner", bugMaxAssigner);


        // 昨日完成、昨日新增
        Date[] dayStartAndEnd = getDayStartAndEnd(-1);
        ForgeProject forgeProjectTime = new ForgeProject();
        forgeProjectTime.setCreateTimeS(dayStartAndEnd[0]);
        forgeProjectTime.setCreateTimeE(dayStartAndEnd[1]);
        buildDayWeekMonthData(forgeProjectTime, res, dayStartAndEnd);

        return res;
    }

    private void buildDayWeekMonthData(ForgeProject forgeProjectTime, Map<String, Object> res, Date[] dayStartAndEnd) {
        //        昨日新增需求
        forgeProjectTime.setPmIssueType(NEED);
        Long yesterdayAddNeed = statisForgeMapper.countForgeProject(forgeProjectTime);
        res.put("yesterdayAddNeed", yesterdayAddNeed);
//昨日新增 任务
        forgeProjectTime.setPmIssueType(TASK);
        Long yesterdayAddTask = statisForgeMapper.countForgeProject(forgeProjectTime);
        res.put("yesterdayAddTask", yesterdayAddTask);
//昨日新增 缺陷
        forgeProjectTime.setPmIssueType(BUG);
        Long yesterdayAddBug = statisForgeMapper.countForgeProject(forgeProjectTime);
        res.put("yesterdayAddBug", yesterdayAddBug);

        ForgeProject forgeProjectFinish = new ForgeProject();
        forgeProjectFinish.setStatusIds(ISSUE_FINISHED);
        forgeProjectFinish.setUpdateTimeS(dayStartAndEnd[0]);
        forgeProjectFinish.setUpdateTimeE(dayStartAndEnd[1]);
        //昨日任务完结
        forgeProjectFinish.setPmIssueType(TASK);
        Long yesterdayFinishTask = statisForgeMapper.countForgeProject(forgeProjectFinish);
        res.put("yesterdayFinishTask", yesterdayFinishTask);
        //昨日缺陷关闭数
        forgeProjectFinish.setPmIssueType(BUG);
        Long yesterdayFinishBug = statisForgeMapper.countForgeProject(forgeProjectFinish);
        res.put("yesterdayFinishBug", yesterdayFinishBug);
//        昨日需求评审数
        forgeProjectFinish.setPmIssueType(NEED);
        Long yesterdayFinishNeed = statisForgeMapper.countForgeProject(forgeProjectFinish);
        res.put("yesterdayFinishNeed", yesterdayFinishNeed);
        //昨日测试用例执行
        ForgeProject forgeProjectTest = new ForgeProject();
        forgeProjectFinish.setStatusIds(Arrays.asList(TASK_CASE_STATUS_PASS, TASK_CASE_STATUS_FAIL, TASK_CASE_STATUS_BLOCK, TASK_CASE_STATUS_SKIP));
        forgeProjectFinish.setUpdateTimeS(dayStartAndEnd[0]);
        forgeProjectFinish.setUpdateTimeE(dayStartAndEnd[1]);
        Long yesterdayTestCase = statisPmsMapper.countTestCaseInSheet(forgeProjectTest);
        res.put("yesterdayTestCase", yesterdayTestCase);

        // 昨日最活跃项目
        List<ZonePmsProject> zonePmsProjects = statisPmsMapper.selectPmsProjectList();
        long pmsProjectIdMax = 0L, maxVal = -1L;
        for (ZonePmsProject p : zonePmsProjects) {
            ForgeProject f = new ForgeProject();
            f.setCreateTimeS(dayStartAndEnd[0]);
            f.setCreateTimeE(dayStartAndEnd[1]);
            f.setUpdateTimeS(dayStartAndEnd[0]);
            f.setUpdateTimeE(dayStartAndEnd[1]);
            f.setPmProjectId(p.getId());

            f.setPmIssueType(NEED);
            Long a = statisForgeMapper.countForgeProjectByCUES(f);
            f.setPmIssueType(TASK);
            Long b = statisForgeMapper.countForgeProjectByCUES(f);
            f.setPmIssueType(BUG);
            Long c = statisForgeMapper.countForgeProjectByCUES(f);
            Long d = statisPmsMapper.countSprintByCUES(f);
            Long e = statisPmsMapper.countTestCaseByCUES(f);

            long total = a + b + c + d + e;
            if (total > maxVal) {
                pmsProjectIdMax = p.getId();
                maxVal = total;
            }
        }

        ZonePmsProject zonePmsProjectMax = statisPmsMapper.selectPmsProjectById(pmsProjectIdMax);
        res.put("zonePmsProjectMax", zonePmsProjectMax==null? "": zonePmsProjectMax.getProjectName());
    }

    public List<ProjectSituationVO> projectSituation() {

        List<ZonePmsProject> zonePmsProjects = statisPmsMapper.selectPmsProjectList();
        List<Long> showProjectList = statisPmsMapper.selectPmsProjectListByDict()
                .stream().filter(Objects::nonNull)
                .collect(Collectors.toList());

        if (!showProjectList.isEmpty()) {
            zonePmsProjects = zonePmsProjects.stream().filter(e->showProjectList.contains(e.getId()))
                    .collect(Collectors.toList());
        }
        List<ProjectSituationVO> res = new ArrayList<>();
        zonePmsProjects.forEach(zonePmsProject -> {

            ProjectSituationVO vo = new ProjectSituationVO();
            BeanUtils.copyProperties(zonePmsProject, vo);

            Map<Integer, Long> sprintCountMap = statisPmsMapper.countSprintByStatus(zonePmsProject.getId())
                    .stream()
                    .collect(Collectors.toMap(KeyValVO::getKey, KeyValVO::getVal, (o, n) -> n));

            vo.setSprintFinishedCount(sprintCountMap.getOrDefault(SPRINT_STATUS_CLOSED,0L));
            vo.setSprintCount(sprintCountMap.values().stream().reduce(0L, Long::sum));

            ForgeProject forgeProject = new ForgeProject();
            forgeProject.setPmProjectId(zonePmsProject.getId());
            forgeProject.setPmIssueType(NEED);
            Long planCount = statisForgeMapper.countForgeProject(forgeProject);
            vo.setNeedCount(planCount);
            forgeProject.setStatusIds(ISSUE_FINISHED);
            Long planFinishCount = statisForgeMapper.countForgeProject(forgeProject);
            vo.setNeedFinishedCount(planFinishCount);
            forgeProject.setPmIssueType(TASK);
            Long taskFinishCount = statisForgeMapper.countForgeProject(forgeProject);
            vo.setTaskFinishedCount(taskFinishCount);
            forgeProject.setStatusIds(new ArrayList<>());
            Long taskCount = statisForgeMapper.countForgeProject(forgeProject);
            vo.setTaskCount(taskCount);

            //           测试相关
            //测试用例数
            Long testCaseCount = statisPmsMapper.countTestCaseBy(zonePmsProject.getId());
            forgeProject.setPmIssueType(BUG);
            forgeProject.setStatusIds(ISSUE_NOT_FINISHED);
            vo.setTestCaseCount(testCaseCount);
//            测试缺陷数
            Long testBugCount = statisForgeMapper.countForgeProject(forgeProject);
            vo.setTestBugCount(testBugCount);
//           测试用例未执行数
            forgeProject.setStatusIds(Collections.singletonList(TASK_CASE_STATUS_NOT_EXEC));
            Long notExecTestCaseCount = statisPmsMapper.countTestCaseInSheet(forgeProject);
            vo.setNotExecTestCaseCount(notExecTestCaseCount);

            res.add(vo);
        });

        return res;
    }

    public Map<String, Object> weekMonthWorkSituation(String type) {
        Map<String, Object> res = new HashMap<>();
        Date[] dayStartAndEnd = getDayStartAndEnd(-1);
        if (Objects.equals(type, "week")) {
            dayStartAndEnd = getCurrentWeek();
        } else if (Objects.equals(type, "month")) {
            dayStartAndEnd = getCurrentMonth();
        }
        ForgeProject forgeProjectTime = new ForgeProject();
        forgeProjectTime.setCreateTimeS(dayStartAndEnd[0]);
        forgeProjectTime.setCreateTimeE(dayStartAndEnd[1]);
        buildDayWeekMonthData(forgeProjectTime, res, dayStartAndEnd);

        return res;
    }
}
