package com.zd.laboratory.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.zd.common.core.enums.HazardTypeEnum;
import com.zd.common.core.exception.ServiceException;
import com.zd.common.core.utils.DateUtils;
import com.zd.laboratory.domain.LabHazard;
import com.zd.laboratory.domain.LabHazardSubjectRelation;
import com.zd.laboratory.domain.dto.LabHazardDTO;
import com.zd.laboratory.domain.dto.LabHazardJoinSubDTO;
import com.zd.laboratory.domain.vo.LabHazardSubVO;
import com.zd.laboratory.domain.vo.LabHazardVO;
import com.zd.laboratory.mapper.LabHazardMapper;
import com.zd.laboratory.mapper.LabHazardSubjectRelationMapper;
import com.zd.laboratory.service.ILabHazardSubjectRelationService;
import com.zd.system.api.factory.RemoteFileFallbackFactory;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

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

/**
 * 危险源和实验室关联Service业务层处理
 *
 * @author zd
 * @date 2021-09-01
 */
@Service
public class LabHazardSubjectRelationServiceImpl implements ILabHazardSubjectRelationService {

    private static final Logger log = LoggerFactory.getLogger(LabHazardSubjectRelationServiceImpl.class);

    @Autowired
    private LabHazardSubjectRelationMapper labHazardSubjectRelationMapper;
    @Autowired
    private LabHazardMapper labHazardMapper;

    /**
     * 查询危险源和实验室关联
     *
     * @param id 危险源和实验室关联主键
     * @return 危险源和实验室关联
     */
    @Override
    public LabHazardSubjectRelation selectLabHazardSubjectRelationById(Long id) {
        return labHazardSubjectRelationMapper.selectLabHazardSubjectRelationById(id);
    }

    /**
     * 查询危险源位置-指定实验室(不包含压力容器)
     *
     * @param subId 实验室ID
     * @return 危险源和实验室关联
     */
    @Override
    public List<LabHazardSubjectRelation> queryHazardSubList(Long subId) {
        LabHazardSubjectRelation subjectRelation = new LabHazardSubjectRelation();
        subjectRelation.setSubjectId(subId);
        subjectRelation.setHazardType(HazardTypeEnum.HAZARD);
        return selectLabHazardSubjectRelationList(subjectRelation);
    }

    /**
     * 查询危险源VO(包含坐标数据)-指定实验室(不包含压力容器)
     *
     * @param subId 实验室ID
     * @return 危险源和实验室关联
     */
    @Override
    public List<LabHazardSubVO> queryHazardSubListVO(Long subId) {
        //获取位置
        List<LabHazardSubjectRelation> labHazardSubjectRelations = queryHazardSubList(subId);
        if (CollUtil.isEmpty(labHazardSubjectRelations)) return Collections.emptyList();
        //获取危险源
        // 危险源IDS
//        Long[] longs = labHazardSubjectRelations.stream().map(a -> a.getHazardId()).toArray(Long[]::new);
//        List<LabHazard> hazards = labHazardMapper.getHazardsByIds(longs);
//        Map<Long, LabHazardSubjectRelation> collect = labHazardSubjectRelations.stream().collect(Collectors.toMap(a -> a.getHazardId(), Function.identity()));
        return Optional.ofNullable(labHazardSubjectRelations).orElse(Collections.emptyList())
                .stream().map(a -> {
                    LabHazard hazards = labHazardMapper.selectLabHazardById(a.getHazardId());
                    LabHazardSubVO hazardSubVO = new LabHazardSubVO(a, hazards);
                    return hazardSubVO;
                }).collect(Collectors.toList());
    }

    /**
     * 查询危险源和实验室关联列表
     *
     * @param labHazardSubjectRelation 危险源和实验室关联
     * @return 危险源和实验室关联
     */
    @Override
    public List<LabHazardSubjectRelation> selectLabHazardSubjectRelationList(LabHazardSubjectRelation labHazardSubjectRelation) {
        return labHazardSubjectRelationMapper.selectLabHazardSubjectRelationList(labHazardSubjectRelation);
    }

    /**
     * 新增危险源和实验室关联
     *
     * @param labHazardSubjectRelation 危险源和实验室关联
     * @return 结果
     */
    @Override
    public int insertLabHazardSubjectRelation(LabHazardSubjectRelation labHazardSubjectRelation) {
        labHazardSubjectRelation.setCreateTime(DateUtils.getNowDate());
        return labHazardSubjectRelationMapper.insertLabHazardSubjectRelation(labHazardSubjectRelation);
    }

    /**
     * 修改危险源和实验室关联
     *
     * @param labHazardSubjectRelation 危险源和实验室关联
     * @return 结果
     */
    @Override
    public int updateLabHazardSubjectRelation(LabHazardSubjectRelation labHazardSubjectRelation) {
        return labHazardSubjectRelationMapper.updateLabHazardSubjectRelation(labHazardSubjectRelation);
    }

    /**
     * 批量删除危险源和实验室关联
     *
     * @param ids 需要删除的危险源和实验室关联主键
     * @return 结果
     */
    @Override
    public int deleteLabHazardSubjectRelationByIds(Long[] ids) {
        return labHazardSubjectRelationMapper.deleteLabHazardSubjectRelationByIds(ids);
    }

    /**
     * 删除危险源和实验室关联信息
     *
     * @param id 危险源和实验室关联主键
     * @return 结果
     */
    @Override
    public int deleteLabHazardSubjectRelationById(Long id) {
        return labHazardSubjectRelationMapper.deleteLabHazardSubjectRelationById(id);
    }

    /**
     * 通过危险源查询关联的实验室
     *
     * @return
     */
    @Override
    public List<LabHazardSubjectRelation> queryLabByHazardId(LabHazardDTO labHazard) {
        return labHazardSubjectRelationMapper.queryLabByHazardId(labHazard);
    }

    /**
     * 更新危险源与实验室关系
     *
     * @param hazardJoinSubDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSubHazardsRelation(LabHazardJoinSubDTO hazardJoinSubDTO, HazardTypeEnum hazardTypeEnum) {
        //更新或保存数据
        Map<Integer, List<LabHazardSubjectRelation>> collect = Optional.ofNullable(hazardJoinSubDTO.getHazardSubVOS())
                .orElse(Collections.emptyList())
                .stream()
                .map(a -> {
                    LabHazardSubjectRelation hazardSubjectRelation = getLabHazardSubjectRelation(hazardTypeEnum, a, hazardJoinSubDTO.getSubId());
                    return hazardSubjectRelation;
                })
                .collect(Collectors.groupingBy(a -> {
                    if (a.getId() == null) return 0;
                    return 1;
                }));

        //todo 先循环处理,不考虑性能， 已经对数据分类，此处可以优化
        collect.entrySet().forEach(a -> {
            if (a.getKey().equals(0)) {
                a.getValue().forEach(b -> {
                    labHazardSubjectRelationMapper.insertLabHazardSubjectRelation(b);
                });
            } else {
                a.getValue().forEach(b -> {
                    labHazardSubjectRelationMapper.updateLabHazardSubjectRelation(b);
                });
            }
        });
        //删除关系
        if (CollUtil.isNotEmpty(hazardJoinSubDTO.getDelIds())) {
            labHazardSubjectRelationMapper.deleteSubLabHazardSubjectRelationByIds(hazardJoinSubDTO.getDelIds().toArray(new Long[hazardJoinSubDTO.getDelIds().size()]), hazardJoinSubDTO.getSubId());
        }

    }

    /**
     * 生成关联数据
     *
     * @param hazardTypeEnum
     * @param a
     * @return
     */
    private LabHazardSubjectRelation getLabHazardSubjectRelation(HazardTypeEnum hazardTypeEnum, LabHazardSubVO a, Long subId) {
        LabHazardSubjectRelation hazardSubjectRelation = new LabHazardSubjectRelation();
        hazardSubjectRelation.setHazardId(a.getId());
        hazardSubjectRelation.setxPoint(a.getxPoint());
        hazardSubjectRelation.setyPoint(a.getyPoint());
        if (a.getXyId() == null) {
            hazardSubjectRelation.setHazardType(hazardTypeEnum);
            hazardSubjectRelation.setSubjectId(subId);
        }
        hazardSubjectRelation.setId(a.getXyId());
        return hazardSubjectRelation;
    }

    /**
     * 将危险源关联到多个实验室-第一版弃用
     */
    @Deprecated
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addRelation(LabHazardDTO labHazard) {
        //验证
        //获取危险品
        if (HazardTypeEnum.HAZARD.equals(labHazard.getHazardType())) {
            Assert.notNull(labHazardMapper.selectLabHazardById(labHazard.getHazardId()), "危险品不存在");
        } else {
            //获取其他
            throw new IllegalArgumentException("未处理的危险品！");
        }

        List<LabHazardSubjectRelation> hazardSubjectList = labHazard.getHazardSubjectList();
        if (CollectionUtils.isEmpty(hazardSubjectList)) {
            throw new ServiceException("关联的实验室不能为空！");
        }

        // 查询现有的关联数据
        List<LabHazardSubjectRelation> hazardSubjects = labHazardSubjectRelationMapper.queryLabByHazardId(labHazard);

        // 要删除的id集合
        List<Long> delIds = new ArrayList<>();
        boolean isContinue;
        for (LabHazardSubjectRelation hazardSubject : hazardSubjects) {
            isContinue = false;
            for (LabHazardSubjectRelation labHazardSubjectRelation : hazardSubjectList) {
                labHazardSubjectRelation.setHazardType(labHazard.getHazardType());
                if (hazardSubject.getId().equals(labHazardSubjectRelation.getId())) {
                    isContinue = true;
                    break;
                }
            }
            if (isContinue) {
                continue;
            }
            delIds.add(hazardSubject.getId());
        }

        labHazardSubjectRelationMapper.insertOrUpdateBatch(hazardSubjectList);
        log.info("addRelation  删除危险源管理的实验室数据 {}", delIds);
        if (delIds.size() > 0) {
            // 删除不存在的数据
            Long[] ids = new Long[delIds.size()];
            labHazardSubjectRelationMapper.deleteLabHazardSubjectRelationByIds(ids);
        }
    }

    @Override
    public int updateBySubId(List<LabHazardSubjectRelation> hazardRelations, Long subId) {
        labHazardSubjectRelationMapper.deleteBySubId(subId);
        for(LabHazardSubjectRelation subjectRelation:hazardRelations){
            labHazardSubjectRelationMapper.insertLabHazardSubjectRelation(subjectRelation);
        }
        return 1;
    }
}
