package com.microservices.pms.project.service.impl;

import com.microservices.common.core.exception.ServiceException;
import com.microservices.common.core.utils.DateUtils;
import com.microservices.common.core.utils.PageUtils;
import com.microservices.common.core.utils.StringUtils;
import com.microservices.common.core.web.page.GenericsTableDataInfo;
import com.microservices.common.security.utils.SecurityUtils;
import com.microservices.pms.common.service.IPmsCommonService;
import com.microservices.pms.enums.TestCaseStatus;
import com.microservices.pms.enums.TestsheetStatus;
import com.microservices.pms.project.domain.PmsProjectTestsheet;
import com.microservices.pms.project.domain.PmsProjectTestsheetCases;
import com.microservices.pms.project.domain.vo.PmsProjectTestsheetSearchVo;
import com.microservices.pms.project.domain.vo.PmsProjectTestsheetVo;
import com.microservices.pms.project.mapper.PmsProjectSprintMapper;
import com.microservices.pms.project.mapper.PmsProjectTestsheetCasesMapper;
import com.microservices.pms.project.mapper.PmsProjectTestsheetIssuesMapper;
import com.microservices.pms.project.mapper.PmsProjectTestsheetMapper;
import com.microservices.pms.project.service.IPmsProjectService;
import com.microservices.pms.project.service.IPmsProjectTestsheetService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 测试单Service业务层处理
 *
 * @author microservices
 * @date 2023-11-24
 */
@Service
public class PmsProjectTestsheetServiceImpl implements IPmsProjectTestsheetService {
    @Autowired
    private PmsProjectTestsheetMapper pmsProjectTestsheetMapper;

    @Autowired
    private PmsProjectSprintMapper pmsProjectSprintMapper;

    @Autowired
    private PmsProjectTestsheetCasesMapper pmsProjectTestsheetCasesMapper;

    @Autowired
    private PmsProjectTestsheetIssuesMapper pmsProjectTestsheetIssuesMapper;

    @Autowired
    private IPmsCommonService pmsCommonService;

    @Autowired
    @Lazy
    private IPmsProjectService pmsProjectService;


    /**
     * 查询测试单
     *
     * @param id 测试单主键
     * @return 测试单
     */
    @Override
    public PmsProjectTestsheet selectPmsProjectTestsheetById(Long id) {
        PmsProjectTestsheet pmsProjectTestsheet = pmsProjectTestsheetMapper.selectPmsProjectTestsheetById(id);
        if (pmsProjectTestsheet == null) {
            throw new ServiceException("该测试单不存在(测试单ID[%s])", id);
        }
        pmsProjectService.selectAndCheckPmsProjectById(pmsProjectTestsheet.getPmsProjectId());
        return pmsProjectTestsheet;
    }

    @Override
    public PmsProjectTestsheetVo selectPmsProjectTestsheetByVoId(Long id) {
        PmsProjectTestsheet db = this.selectPmsProjectTestsheetById(id);
        return buildPmsProjectTestsheetVo(db);
    }


    /**
     * 查询测试单列表
     *
     * @param searchVo 测试单
     * @return 测试单
     */
    @Override
    public GenericsTableDataInfo<PmsProjectTestsheetVo> selectPmsProjectTestsheetList(PmsProjectTestsheetSearchVo searchVo) {
        pmsProjectService.selectPmsProjectById(searchVo.getPmsProjectId());
        PageUtils.startPage();
        PmsProjectTestsheet testsheet = new PmsProjectTestsheet();
        BeanUtils.copyProperties(searchVo, testsheet);
        List<PmsProjectTestsheet> list = pmsProjectTestsheetMapper.selectPmsProjectTestsheetList(testsheet);
        return PageUtils.toPage(list, this::buildPmsProjectTestsheetVo);
    }

    /**
     * 新增测试单
     *
     * @param pmsProjectTestsheet 测试单
     * @return 结果
     */
    @Override
    public int insertPmsProjectTestsheet(PmsProjectTestsheet pmsProjectTestsheet) {
        pmsProjectService.selectPmsProjectById(pmsProjectTestsheet.getPmsProjectId());
        if (pmsProjectTestsheet.getAssigneeId() != null) {
            pmsCommonService.getSimpleSysUserByGitlinkUserId(pmsProjectTestsheet.getAssigneeId());
        }
        if (pmsProjectTestsheet.getBeginTime() != null && pmsProjectTestsheet.getEndTime() != null) {
            if (pmsProjectTestsheet.getBeginTime().after(pmsProjectTestsheet.getEndTime())) {
                throw new ServiceException("开始时间不能晚于结束时间");
            }
        }
        if ((pmsProjectTestsheet.getBeginTime() == null && pmsProjectTestsheet.getEndTime() != null) || (pmsProjectTestsheet.getBeginTime() != null && pmsProjectTestsheet.getEndTime() == null)) {
            throw new ServiceException("开始时间结束时间需要同时设置");
        }
        pmsProjectTestsheet.setCreateBy(SecurityUtils.getUsername());
        pmsProjectTestsheet.setCreateTime(DateUtils.getNowDate());
        pmsProjectTestsheet.setStatus((long) TestsheetStatus.INIT.ordinal());
        return pmsProjectTestsheetMapper.insertPmsProjectTestsheet(pmsProjectTestsheet);
    }

    /**
     * 修改测试单
     *
     * @param pmsProjectTestsheet 测试单
     * @return 结果
     */
    @Override
    public int updatePmsProjectTestsheet(PmsProjectTestsheet pmsProjectTestsheet) {
        selectPmsProjectTestsheetById(pmsProjectTestsheet.getId());
        if (pmsProjectTestsheet.getAssigneeId() !=null){
            pmsCommonService.getSimpleSysUserByGitlinkUserId(pmsProjectTestsheet.getAssigneeId());
        }
        if (pmsProjectTestsheet.getBeginTime() != null && pmsProjectTestsheet.getEndTime() != null) {
            if (pmsProjectTestsheet.getBeginTime().after(pmsProjectTestsheet.getEndTime())) {
                throw new ServiceException("开始时间不能晚于结束时间");
            }
        }
        if ((pmsProjectTestsheet.getBeginTime() == null && pmsProjectTestsheet.getEndTime() != null) || (pmsProjectTestsheet.getBeginTime() != null && pmsProjectTestsheet.getEndTime() == null)) {
            throw new ServiceException("开始时间结束时间需要同时设置");
        }
        pmsProjectTestsheet.setUpdateBy(SecurityUtils.getUsername());
        pmsProjectTestsheet.setUpdateTime(DateUtils.getNowDate());
        return pmsProjectTestsheetMapper.updatePmsProjectTestsheet(pmsProjectTestsheet);
    }

    /**
     * 批量删除测试单
     *
     * @param ids 需要删除的测试单主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deletePmsProjectTestsheetByIds(Long[] ids) {
        List<PmsProjectTestsheetCases> testsheetCasesList = pmsProjectTestsheetCasesMapper.selectPmsProjectTestsheetCasesListBy(ids);
        if (!testsheetCasesList.isEmpty()) {
            Long[] testsheetCasesIds = testsheetCasesList.stream().map(PmsProjectTestsheetCases::getId).toArray(Long[]::new);
            pmsProjectTestsheetCasesMapper.deletePmsProjectTestsheetCasesByIds(testsheetCasesIds);
            pmsProjectTestsheetIssuesMapper.deleteByProjectTestsheetCasesIds(testsheetCasesIds);
        }
        return pmsProjectTestsheetMapper.deletePmsProjectTestsheetByIds(ids);
    }

    public List<PmsProjectTestsheetVo> selectPmsProjectTestsheetVosByIds(String testSheetIds) {
        List<PmsProjectTestsheet> pmsProjectTestsheetList = pmsProjectTestsheetMapper.selectPmsProjectTestsheetByIds(testSheetIds);
        return pmsProjectTestsheetList.stream().map(this::buildPmsProjectTestsheetVo).collect(Collectors.toList());
    }

    private PmsProjectTestsheetVo buildPmsProjectTestsheetVo(PmsProjectTestsheet db) {
        PmsProjectTestsheetVo testsheetVo = new PmsProjectTestsheetVo();
        BeanUtils.copyProperties(db, testsheetVo);
        // 负责人
        testsheetVo.setAssigneeUser(pmsCommonService.getSimpleSysUserByGitlinkUserId(db.getAssigneeId()));
        // 关联迭代
        if (StringUtils.isNotNull(db.getProjectSprintId())) {
            testsheetVo.setProjectSprintIdStr(pmsProjectSprintMapper.selectPmsProjectSprintById(db.getProjectSprintId()) == null ? "" : pmsProjectSprintMapper.selectPmsProjectSprintById(db.getProjectSprintId()).getSprintName());
        }
        // 计算通过率
        PmsProjectTestsheetCases queryTestsheetCases = new PmsProjectTestsheetCases();
        queryTestsheetCases.setProjectTestsheetId(db.getId());
        List<PmsProjectTestsheetCases> testsheetCasesList = pmsProjectTestsheetCasesMapper.selectPmsProjectTestsheetCasesList(queryTestsheetCases);
        Long passCount = Optional.ofNullable(testsheetCasesList).orElse(Collections.emptyList()).stream()
                .filter(testCase -> testCase.getTestStatus().intValue() == TestCaseStatus.PASS.ordinal()).count();
        // 总 = 失败+通过+阻塞+未执行(或者排除跳过的)
        Long execTotalCount = Optional.ofNullable(testsheetCasesList).orElse(Collections.emptyList()).stream()
                .filter(testCase -> testCase.getTestStatus().intValue() != TestCaseStatus.SKIP.ordinal()).count();
        // 通过率
        Double passRate = execTotalCount == 0 ? 0 : BigDecimal.valueOf(passCount / execTotalCount.doubleValue()).setScale(3, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100)).doubleValue();
        testsheetVo.setPassRate(passRate);
        // 通过详情
        Map<Long, Integer> passDetail = Optional.ofNullable(testsheetCasesList).orElse(Collections.emptyList()).stream()
                .collect(Collectors.groupingBy(PmsProjectTestsheetCases::getTestStatus, Collectors.summingInt(value -> 1)));
        testsheetVo.setPassDetail(passDetail);
        // 执行用例数和总用例数
        Long execCount = Optional.ofNullable(testsheetCasesList).orElse(Collections.emptyList()).stream()
                .filter(testCase -> testCase.getTestStatus().intValue() != TestCaseStatus.INIT.ordinal()).count();
        testsheetVo.setTotalCount(testsheetCasesList != null ? testsheetCasesList.size() : 0);
        testsheetVo.setExecCount(execCount.intValue());
        // 更新状态
        if (passRate > 0) {
            db.setStatus((long) (passRate == 100 ? TestsheetStatus.FINISHED.ordinal() : TestsheetStatus.RUNNING.ordinal()));
            testsheetVo.setStatus(db.getStatus());
            pmsProjectTestsheetMapper.updatePmsProjectTestsheet(db);
        }
        // 移除所有增加用例后更新状态初始值
        if (execTotalCount == 0 && db.getStatus().intValue() != TestsheetStatus.INIT.ordinal()) {
            db.setStatus((long) TestsheetStatus.INIT.ordinal());
            testsheetVo.setStatus(db.getStatus());
            pmsProjectTestsheetMapper.updatePmsProjectTestsheet(db);
        }
        // 是否逾期
        if (db.getEndTime() != null && db.getStatus().intValue() != TestsheetStatus.FINISHED.ordinal()
                && DateUtils.getNowDate().compareTo(DateUtils.parseDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, db.getEndTime()) + " 23:59:59")) > 0) {
            testsheetVo.setIsDelay(true);
        }
        return testsheetVo;
    }
}
