package com.xinyilu.system.service.testItem.impl;

import com.xinyilu.common.constant.Constants;
import com.xinyilu.common.core.domain.AjaxResult;
import com.xinyilu.common.exception.ServiceException;
import com.xinyilu.common.utils.DateUtils;
import com.xinyilu.common.utils.SecurityUtils;
import com.xinyilu.common.utils.bean.BeanUtils;
import com.xinyilu.system.domain.dto.TestItemsDTO;
import com.xinyilu.system.domain.testItem.TestItems;
import com.xinyilu.system.domain.testItemStandard.TestItemStandard;
import com.xinyilu.system.domain.testLevel.TestItemLevel;
import com.xinyilu.system.domain.testcategoryitem.TestCategoryItem;
import com.xinyilu.system.domain.vo.TestItemsVO;
import com.xinyilu.system.mapper.testItem.TestItemsMapper;
import com.xinyilu.system.mapper.testItemLevel.TestItemLevelMapper;
import com.xinyilu.system.mapper.testItemStandard.TestItemStandardMapper;
import com.xinyilu.system.mapper.testcategoryitem.TestCategoryItemMapper;
import com.xinyilu.system.service.testItem.ITestItemsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 测试项目Service业务层处理
 *
 * @author jihan
 * @date 2022-08-02
 */
@Slf4j
@Service
public class TestItemsServiceImpl implements ITestItemsService {

    @Resource
    private TestItemsMapper testItemsMapper;
    @Resource
    private TestItemStandardMapper testItemStandardMapper;
    @Resource
    private TestItemLevelMapper testItemLevelMapper;
    @Resource
    private TestCategoryItemMapper testCategoryItemMapper;

    /**
     * 查询测试项目
     *
     * @param id 测试项目主键
     * @return 测试项目
     */
    @Override
    public TestItemsVO selectTestItemsById(Long id) {
        //查询测试项目信息
        TestItemsVO testItemsVO = testItemsMapper.selectTestItemsById(id);
        if (Objects.isNull(testItemsVO)) {
            return new TestItemsVO();
        }
        //查询分类id
        testItemsVO.setTestCategoryItemList(testCategoryItemMapper.getItemCategoryIds(id));
        //查询测试项目成绩级别信息
        TestItemLevel testItemLevel = new TestItemLevel();
        testItemLevel.setItemId(id);
        List<TestItemLevel> itemLevelList = testItemLevelMapper.selectTestItemLevelList(testItemLevel);
        if (CollectionUtils.isNotEmpty(itemLevelList)) {
            testItemsVO.setItemLevelList(itemLevelList);
        }
        return testItemsVO;
    }

    /**
     * 查询测试项目列表
     *
     * @param testItems 测试项目
     * @return 测试项目
     */
    @Override
    public List<TestItemsVO> selectTestItemsList(TestItems testItems) {
        return testItemsMapper.selectTestItemsList(testItems);
    }

    /**
     * 新增测试项目
     *
     * @param testItems 测试项目
     * @param createBy  创建人
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult insertTestItems(TestItemsDTO testItems, String createBy) {
        if (CollectionUtils.isEmpty(testItems.getTestCategoryItemList())) {
            return AjaxResult.error("请选择测试项目所属分类！");
        }
        if (Objects.nonNull(testItems.getMinScore()) && Objects.nonNull(testItems.getMaxScore())) {
            if (testItems.getMinScore().compareTo(testItems.getMaxScore()) >= 0) {
                return AjaxResult.error("最低得分不能大于最高得分");
            }
        }
        //判断项目编号是否唯一
        int itemCodeCount = testItemsMapper.selectItemCodeInfo(testItems.getItemCode(), null);
        if (itemCodeCount > 0) {
            return AjaxResult.error("项目编号：" + testItems.getItemCode() + "已存在，请重新输入");
        }
        //判断项目名称是否唯一
        int itemNameCount = testItemsMapper.selectItemCodeInfo(null, testItems.getItemName());
        if (itemNameCount > 0) {
            return AjaxResult.error("项目名称：" + testItems.getItemName() + "已存在，请重新输入");
        }
        //创建人
        testItems.setCreateBy(createBy);
        testItems.setCreateTime(DateUtils.getNowDate());
        testItems.setDelFlag(0);
        //新增测试项目主表信息
        int insertTestItemsCount = testItemsMapper.insertTestItems(testItems);
        if (insertTestItemsCount <= 0) {
            log.info("新增测试项目失败，新增信息为testItems=[{}]", testItems);
            throw new ServiceException("新增测试项目信息失败");
        }
        //新增测试项目分类信息
        this.insertTestCategoryItem(testItems.getTestCategoryItemList(), testItems.getId());
        //测试项目主表id
        if (Objects.isNull(testItems.getId())) {
            log.info("测试项目表id获取失败");
            throw new ServiceException("新增测试项目信息失败");
        }
        Long itemsId = testItems.getId();
        TestItemStandard testItemStandard = new TestItemStandard();
        testItems.setTestItemsId(itemsId);
        BeanUtils.copyProperties(testItems, testItemStandard);
        //新增测试项目区间表信息
        int itemStandardCount = testItemStandardMapper.insertTestItemStandard(testItemStandard);
        if (itemStandardCount <= 0) {
            log.info("新增测试项目区间表信息失败，新增数据为testItemStandard=[{}]", testItemStandard);
            throw new ServiceException("新增测试项目区间信息表失败");
        }
        if (CollectionUtils.isEmpty(testItems.getItemLevelList())) {
            return AjaxResult.success();
        }
        //新增测试项目成绩级别信息
        this.insertItemLevel(testItems.getItemLevelList(), itemsId, createBy);
        return AjaxResult.success();
    }

    /**
     * 修改测试项目
     *
     * @param testItems 测试项目
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult updateTestItems(TestItemsDTO testItems, String updateBy) {
        if (CollectionUtils.isEmpty(testItems.getTestCategoryItemList())) {
            return AjaxResult.error("请选择测试项目所属分类！");
        }
        if (Objects.nonNull(testItems.getMinScore()) && Objects.nonNull(testItems.getMaxScore())) {
            if (testItems.getMinScore().compareTo(testItems.getMaxScore()) >= 0) {
                return AjaxResult.error("最低得分不能大于最高得分");
            }
        }
        TestItemsVO testItemsVO = testItemsMapper.selectTestItemsById(testItems.getId());
        if (Objects.isNull(testItemsVO)) {
            return AjaxResult.error("当前项目信息不存在");
        }
        //判断项目编号是否唯一
        if (!testItems.getItemCode().equals(testItemsVO.getItemCode())) {
            //说明修改了项目编号，则判断新的项目编号是否存在
            int itemCount = testItemsMapper.selectItemCodeInfo(testItems.getItemCode(), null);
            if (itemCount > 0) {
                return AjaxResult.error("项目编号：" + testItems.getItemCode() + "已存在，请重新输入");
            }
        }
        //判断项目名称是否唯一
        if (!testItems.getItemName().equals(testItemsVO.getItemName())) {
            //说明修改了项目编号，则判断新的项目编号是否存在
            int itemCount = testItemsMapper.selectItemCodeInfo(null, testItems.getItemName());
            if (itemCount > 0) {
                return AjaxResult.error("项目名称：" + testItems.getItemName() + "已存在，请重新输入");
            }
        }
        //创建人
        testItems.setUpdateBy(updateBy);
        testItems.setDelFlag(0);
        testItems.setUpdateTime(DateUtils.getNowDate());
        int updateTestItemsCount = testItemsMapper.updateTestItems(testItems);
        //修改测试项目表信息
        if (updateTestItemsCount <= 0) {
            log.info("修改测试项目失败，修改信息为testItems=[{}]", testItems);
            throw new ServiceException("修改测试项目信息失败");
        }
        //修改测试项目分类信息
        this.updateTestCategoryItemInfo(testItems);
        //修改测试项目区间表信息
        TestItemStandard testItemStandard = new TestItemStandard();
        testItems.setTestItemsId(testItems.getId());
        BeanUtils.copyProperties(testItems, testItemStandard);
        int updateItemStandardCount = testItemStandardMapper.updateTestItemStandard(testItemStandard);
        if (updateItemStandardCount <= 0) {
            log.info("修改测试项目区间表信息失败，修改数据为testItemStandard=[{}]", testItemStandard);
            throw new ServiceException("修改测试项目区间信息表失败");
        }
        //根据指标类型清空标准最高得分数据
        if (Constants.UNIFIED_STANDARD.equals(testItems.getStandardType())) {
            //统一
            int unifiedCount = testItemStandardMapper.updateUnifiedStandardScore(updateBy, testItems.getId());
            if (unifiedCount <= 0) {
                log.info("修改统一标准最高得分失败，修改数据为testItemStandard=[{}]", testItemStandard);
                throw new ServiceException("修改统一标准最高得分失败");
            }
        } else if (Constants.DISUNITY_STANDARD.equals(testItems.getStandardType())) {
            //非统一
            int disunityCount = testItemStandardMapper.updateDisunityStandardScore(updateBy, testItems.getId());
            if (disunityCount <= 0) {
                log.info("修改非统一标准最高得分失败，修改数据为testItemStandard=[{}]", testItemStandard);
                throw new ServiceException("修改非统一标准最高得分失败");
            }
        }
        //判断当前项目有没有级别成绩
        int itemLevelCount = testItemLevelMapper.getTestItemLevelByItemId(testItems.getId());
        if (itemLevelCount > 0) {
            int deleteLevelCount = testItemLevelMapper.deleteTestItemLevelById(testItems.getId());
            if (deleteLevelCount <= 0) {
                throw new ServiceException("删除测试项目成绩级别信息失败");
            }
        }
        //新增测试项目成绩级别信息
        this.insertItemLevel(testItems.getItemLevelList(), testItems.getId(), updateBy);
        return AjaxResult.success();
    }

    /**
     * 批量删除测试项目
     *
     * @param ids 需要删除的测试项目主键
     * @return 结果
     */
    @Override
    public int deleteTestItemsByIds(Long[] ids) {
        return testItemsMapper.deleteTestItemsByIds(ids);
    }

    /**
     * 删除测试项目信息
     *
     * @param id 测试项目主键
     * @return 结果
     */
    @Override
    public int deleteTestItemsById(Long id) {
        return testItemsMapper.deleteTestItemsById(id);
    }

    /**
     * 逻辑删除测试项目信息
     *
     * @param ids 需要删除的测试项目主键集合
     * @return int 数量
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult updateTestItemsByIds(Long[] ids) {
        //删除测试项目表信息
        int testItemsCount = testItemsMapper.updateTestItemsByIds(ids);
        if (testItemsCount <= 0) {
            throw new ServiceException("删测试项目信息失败");
        }
        //删除测试项目区间表信息
        int itemStandardByCount = testItemStandardMapper.updateTestItemStandardByIds(ids);
        if (itemStandardByCount <= 0) {
            throw new ServiceException("删测试项目区间信息失败");
        }
        //删除测试项目成绩级别信息
        int itemLevelCount = testItemLevelMapper.getTestItemLevelByItemIds(ids);
        if (itemLevelCount > 0) {
            int testItemLevelCount = testItemLevelMapper.updateTestItemLevelByIds(ids);
            if (testItemLevelCount <= 0) {
                throw new ServiceException("删测试项目成绩级别信息失败");
            }
        }
        //删除测试项目分类信息表
        int updateTestCategoryItems = testCategoryItemMapper.updateTestCategoryItems(ids);
        if (updateTestCategoryItems <= 0) {
            throw new ServiceException("删测试项目分类信息失败");
        }
        return AjaxResult.success();
    }

    /**
     * 根据项目id查询项目成绩级别信息
     *
     * @param itemId 项目id
     * @return List<TestItemLevel> 测试项目级别信息
     */
    @Override
    public List<TestItemLevel> getTestItemLevelInfo(Long itemId) {
        TestItemLevel testItemLevel = new TestItemLevel();
        testItemLevel.setItemId(itemId);
        return testItemLevelMapper.selectTestItemLevelList(testItemLevel);
    }

    /**
     * 根据项目id查询对应的分类信息
     *
     * @param itemId 测试项目id
     * @return 分类信息
     */
    @Override
    public AjaxResult getTestCategoryItemInfo(Long itemId) {
        return AjaxResult.success(testItemsMapper.getCategoryItemInfo(itemId));
    }

    /**
     * 新增测试项目成绩级别信息
     *
     * @param testItemLevelList 项目级别信息集合
     * @param itemsId           项目表id
     * @param createBy          创建人
     */
    private void insertItemLevel(List<TestItemLevel> testItemLevelList, Long itemsId, String createBy) {
        //新增测试项目成绩级别信息
        if (CollectionUtils.isNotEmpty(testItemLevelList)) {
            //判断区间分数是否正确，目前仅支持所有的得分区间都是闭区间
            judgeLevelScore(testItemLevelList);
            //新增区间信息
            for (TestItemLevel level : testItemLevelList) {
                if (Objects.nonNull(level.getLevelName()) && Objects.nonNull(level.getLevelMinScore()) && Objects.nonNull(level.getLevelMaxScore())) {
                    //插入数据
                    insertLevelInfo(level, itemsId, createBy);
                }
            }
        }
    }

    /**
     * 判断测试项目区间分数最小值和最大值是否正确
     *
     * @param testItemLevelList 区间分组信息
     */
    private void judgeLevelScore(List<TestItemLevel> testItemLevelList) {
        //按照区间最小值进行排序
        List<TestItemLevel> itemLevelList = testItemLevelList.stream()
                .filter(item -> Objects.nonNull(item.getLevelMinScore()))
                .sorted(Comparator.comparing(TestItemLevel::getLevelMinScore)).collect(Collectors.toList());
        for (int i = 0; i < itemLevelList.size(); i++) {
            TestItemLevel testItemLevel = itemLevelList.get(i);
            if (Objects.nonNull(testItemLevel.getLevelMinScore()) && Objects.nonNull(testItemLevel.getLevelMaxScore())) {
                if (testItemLevel.getLevelMinScore().compareTo(testItemLevel.getLevelMaxScore()) >= 0) {
                    throw new ServiceException("级别成绩最低得分不能大于级别成绩最高得分！");
                }
            }
            //判断区间分数是否重复
            for (int j = i + 1; j < itemLevelList.size(); j++) {
                if (Objects.nonNull(itemLevelList.get(j).getLevelMinScore()) && Objects.nonNull(testItemLevel.getLevelMaxScore())) {
                    if (itemLevelList.get(j).getLevelMinScore().compareTo(testItemLevel.getLevelMaxScore()) <= 0) {
                        throw new ServiceException("级别成绩最低得分和级别成绩最高得分区间不能重复！");
                    }
                }
            }
        }
    }

    /**
     * 新增区间信息
     *
     * @param level    区间信息
     * @param itemsId  项目id
     * @param createBy 创建人
     **/
    private void insertLevelInfo(TestItemLevel level, Long itemsId, String createBy) {
        //判断项目成绩级别是否为空
        if (Objects.isNull(level.getStandardFlag())) {
            throw new ServiceException("是否达标不能为空！");
        }
        level.setItemId(itemsId);
        level.setDelFlag(0);
        level.setCreateBy(createBy);
        level.setCreateTime(DateUtils.getNowDate());
        int itemLevel = testItemLevelMapper.insertTestItemLevel(level);
        if (itemLevel <= 0) {
            throw new ServiceException("新增测试项目成绩级别信息失败");
        }
    }

    /**
     * 新增测试项目分类关系表信息
     *
     * @param testCategoryItemList 测试项目分类集合
     */
    private void insertTestCategoryItem(List<Long> testCategoryItemList, Long itemId) {
        List<TestCategoryItem> categoryItemList = Lists.newArrayList();
        for (Long categoryItemId : testCategoryItemList) {
            categoryItemList.add(TestCategoryItem.builder().itemCategoryId(categoryItemId).itemId(itemId)
                    .createBy(SecurityUtils.getUsername()).createTime(LocalDateTime.now()).build());
        }
        int insertCount = testCategoryItemMapper.insertBatchTestCategoryInfo(categoryItemList);
        if (insertCount <= 0) {
            throw new ServiceException("新增测试项目分类信息失败，请联系管理员！");
        }
    }

    /**
     * 修改测试项目分类关系表信息
     *
     * @param testItems 输入参数
     */
    private void updateTestCategoryItemInfo(TestItemsDTO testItems) {
        TestCategoryItem testCategoryItem = new TestCategoryItem();
        testCategoryItem.setItemId(testItems.getId());
        List<Long> categoryIdList = testCategoryItemMapper.selectTestCategoryItemList(testCategoryItem).stream().filter(item -> Objects.nonNull(item.getItemCategoryId())).map(TestCategoryItem::getItemCategoryId).collect(Collectors.toList());
        //找出需要删除的分类信息
        List<Long> deleteCategoryIdList = new ArrayList<>(CollectionUtils.subtract(categoryIdList, testItems.getTestCategoryItemList())).stream().distinct().collect(Collectors.toList());
        //找出需要新增的分类信息
        List<Long> insertCategoryIdList = new ArrayList<>(CollectionUtils.subtract(testItems.getTestCategoryItemList(), categoryIdList)).stream().distinct().collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(deleteCategoryIdList)) {
            //删除
            int deleteCount = testCategoryItemMapper.deleteCategoryItemByCategoryIds(testItems.getId(), deleteCategoryIdList);
            if (deleteCount <= 0) {
                throw new ServiceException("修改测试项目分类信息失败，请联系管理员！");
            }
        }
        if (CollectionUtils.isNotEmpty(insertCategoryIdList)) {
            //新增
            List<TestCategoryItem> testCategoryItems = Lists.newArrayList();
            for (Long categoryId : insertCategoryIdList) {
                testCategoryItems.add(TestCategoryItem.builder()
                        .itemCategoryId(categoryId).itemId(testItems.getId())
                        .createBy(SecurityUtils.getUsername()).createTime(LocalDateTime.now()).build());
            }
            int insertCount = testCategoryItemMapper.insertBatchTestCategoryInfo(testCategoryItems);
            if (insertCount <= 0) {
                throw new ServiceException("修改测试项目分类信息失败，请联系管理员！");
            }
        }
    }
}
