package com.yiboshi.science.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yiboshi.arch.exception.BusinessException;
import com.yiboshi.science.base.BaseServiceImpl;
import com.yiboshi.science.base.Pagination;
import com.yiboshi.science.dao.ComProjectDAO;
import com.yiboshi.science.dao.ComProjectGroupDAO;
import com.yiboshi.science.entity.*;
import com.yiboshi.science.param.dto.*;
import com.yiboshi.science.param.query.ComProjectAuditQueryVO;
import com.yiboshi.science.param.query.ComProjectGroupQueryVO;
import com.yiboshi.science.service.*;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
@AllArgsConstructor
public class ComProjectGroupServiceImpl extends BaseServiceImpl<ComProjectGroupDAO, ComProjectGroupQueryVO, ComProjectGroupDTO, ComProjectGroup> implements ComProjectGroupService {
    @Autowired
    private ComProjectGroupDAO comProjectGroupDAO;

    @Autowired
    private ComProjectDAO comProjectDAO;

    @Autowired
    private ComProjectGroupDetailService comProjectGroupDetailService;

    @Autowired
    private ComProjectGroupAssignService comProjectGroupAssignService;

    @Autowired
    private SystemParameterService systemParameterService;

    @Autowired
    private ComProjectAssignService comProjectAssignService;

    @Autowired
    private ComBatchService comBatchService;

    @Autowired
    private ComProjectAuditService comProjectAuditService;

    @Autowired
    private ComProjectMembersService comProjectMembersService;

    @Override
    protected void setCriteriaForQuery(ComProjectGroupQueryVO vo, QueryWrapper<ComProjectGroupQueryVO> criteria) {

        if (Objects.nonNull(vo.getGroupYear())) {
            criteria.eq("group_year", vo.getGroupYear());
        }
        if (Objects.nonNull(vo.getGroupName())) {
            criteria.like("group_name", vo.getGroupName());
        }
        if (Objects.nonNull(vo.getKnowledgeId())) {
            criteria.eq("knowledge_id", vo.getKnowledgeId());
        }
        if (Objects.nonNull(vo.getKnowledgeParentId())) {
            criteria.eq("e.id", vo.getKnowledgeParentId());
        }
        if (Objects.nonNull(vo.getAssignState())) {
            criteria.eq("assign_state", vo.getAssignState());
        }
    }

    public Pagination<ComProjectGroupDTO> getProjectGroupListByPage(ComProjectGroupQueryVO vo) {
        QueryWrapper criteria = new QueryWrapper();
        setCriteriaForQuery(vo, criteria);
        Page<ComProjectGroupQueryVO> page = new Page<>(vo.getPageIndex(), vo.getPageSize());
        List<ComProjectGroupDTO> dtoList = comProjectGroupDAO.getListByPage(page, criteria).getRecords();
        if (null != dtoList && dtoList.size() != 0) {
            dtoList.forEach((e) -> {
                e.setExpertList(comProjectGroupAssignService.getAssignExpertList(e.getId()));
                e.setProjectList(comProjectGroupDetailService.getProjectDetailList(e.getId()));
            });
        }
        return new Pagination<>(dtoList, page.getTotal(), vo.getPageSize());
    }

    private String InsertProjectGroup(int ReportYear, int ProjCount, String ProjGroupName, String KnowledgeId, String Remark) {
        ComProjectGroup entity = new ComProjectGroup();
        entity.setGroupYear(ReportYear);
        entity.setGroupName(ProjGroupName);
        entity.setKnowledgeId(KnowledgeId);
        entity.setProjCount(ProjCount);
        entity.setExpertCount(0);
        entity.setRemark(Remark);
        entity.setAssignState(0);
        return this.insert(entity);
    }

    private void JoinProjectGroup(String groupId, String projId) {
        ComProjectGroupDetailDTO dto = comProjectGroupDetailService.getProjectGroupDetailByGP(groupId, projId);
        if (null == dto) {
            ComProjectGroupDetail detailEntity = new ComProjectGroupDetail();
            detailEntity.setGroupId(groupId);
            detailEntity.setProjId(projId);
            comProjectGroupDetailService.insert(detailEntity);
        }
    }

    @Transactional
    public void processProjectGroup(String ProjectID) {
        ComProjectDTO projDTO = comProjectDAO.getById(ProjectID);

        if (null == projDTO)
            return;

        SystemParameter ParaModel = systemParameterService.getParentModelByChildId(projDTO.getKnowledgeId());
        ComProjectGroupDTO groupDTO = comProjectGroupDAO.getProjectGroupByKnowLedgeIDYear(projDTO.getReportYear(), ParaModel.getId());

        if (null == groupDTO) {
            String groupId = InsertProjectGroup(projDTO.getReportYear(), 1, ParaModel.getName() + "项目组-1", ParaModel.getId(), "");

            JoinProjectGroup(groupId, projDTO.getId());
        } else {
            if (groupDTO.getProjCount() < 30) {
                groupDTO.setProjCount(groupDTO.getProjCount() + 1);
                ComProjectGroup entity = this.convert2Entity(groupDTO);
                this.update(entity);

                JoinProjectGroup(groupDTO.getId(), projDTO.getId());

                if (groupDTO.getExpertCount() > 0) {
                    List<String> projects = new ArrayList();
                    projects.add(projDTO.getId());
                    List<ComProjectGroupAssignDTO> list = comProjectGroupAssignService.getAssignExpertList(groupDTO.getId());
                    List<String> experts = new ArrayList();
                    list.forEach(e -> {
                        experts.add(e.getExpertId());
                    });
                    comProjectAssignService.assignProject(projDTO.getReportYear(), projects, experts);
                }
            } else {
                Integer index = groupDTO.getGroupName().indexOf("-");
                String strContent = groupDTO.getGroupName().substring(index + 1);
                Integer ProjGroupCount = Integer.parseInt(strContent) + 1;
                String ProjGroupName = ParaModel.getName() + "项目组-" + ProjGroupCount;

                String groupId = InsertProjectGroup(projDTO.getReportYear(), 1, ProjGroupName, ParaModel.getId(), "");
                JoinProjectGroup(groupId, projDTO.getId());
            }
        }
    }


    public void CalculateGroupProjectCount(String groupId) {
        List<ComProjectGroupDetailDTO> list = comProjectGroupDetailService.getProjectDetailList(groupId);
        ComProjectGroup model = new ComProjectGroup();
        model.setId(groupId);
        if (null == list || list.size() == 0)
            model.setProjCount(0);
        else
            model.setProjCount(list.size());
        this.update(model);
    }

    public void CalculateGroupExpertCount(String groupId) {
        List<ComProjectGroupAssignDTO> list = comProjectGroupAssignService.getAssignExpertList(groupId);
        ComProjectGroup model = new ComProjectGroup();
        model.setId(groupId);
        if (null == list || list.size() == 0) {
            model.setExpertCount(0);
            model.setAssignState(0);
        } else {
            model.setExpertCount(list.size());
            model.setAssignState(1);
        }
        this.update(model);
    }

    @Transactional
    public boolean addProjectGroupKnowledge(String groupId, List<String> KnowledgeList, ComProjectAuditQueryVO vo) {
        List<ComProject> ProjList = new ArrayList<>();
        KnowledgeList.forEach(e -> {
            vo.setKnowledgeId(e);
            vo.setAuditType(1);
            List<ComProjectAuditDTO> projList = comProjectAuditService.getAuditProjectList(vo);
            if (null != projList && projList.size() > 0) {
                projList.forEach(p -> {
                    ComProject entity = new ComProject();
                    entity.setId(p.getProjId());
                    entity.setKnowledgeId(e);
                    ProjList.add(entity);
                });
            }
        });

        if (ProjList.size() > 0) {
            ProjList.forEach(e -> {
                ComProjectGroupDetail model = new ComProjectGroupDetail();
                model.setProjId(e.getId());
                model.setKnowledgeId(e.getKnowledgeId());
                model.setGroupId(groupId);
                comProjectGroupDetailService.insert(model);
            });

            processGroupProjectExpert(groupId);
            CalculateGroupProjectCount(groupId);
            return true;
        } else return false;
    }

    @Transactional
    public boolean InsertProjectGroup(List<String> IdList, String groupId) {
        ComProjectGroupDTO dto = this.getGroupById(groupId);
        if (null == dto)
            return false;
        IdList.forEach(e -> {
            ComProjectGroupDetail model = new ComProjectGroupDetail();
            model.setProjId(e);
            model.setGroupId(groupId);
            comProjectGroupDetailService.insert(model);
        });
        processGroupProjectExpert(groupId);
        CalculateGroupProjectCount(groupId);
        return true;
    }

    @Transactional
    public boolean updataProjectGroupAdjust(List<String> IdList, String groupId) {
        ComProjectGroupDetail entity = comProjectGroupDetailService.entityById(IdList.get(0));
        String oldGroupId = entity.getGroupId();
        ComProjectGroupDTO dto = this.getGroupById(oldGroupId);
        if (null != dto.getExpertCount() && dto.getExpertCount() > 0)
            return false;
        dto = this.getGroupById(groupId);
        if (null != dto.getExpertCount() && dto.getExpertCount() > 0)
            return false;

        IdList.forEach(e -> {
            ComProjectGroupDetail model = new ComProjectGroupDetail();
            model.setId(e);
            model.setGroupId(groupId);
            comProjectGroupDetailService.update(model);
        });
        CalculateGroupProjectCount(oldGroupId);
        CalculateGroupProjectCount(groupId);
        CalculateGroupExpertCount(oldGroupId);
        CalculateGroupExpertCount(groupId);
        return true;
    }

    public ComProjectGroupDTO getGroupById(String id) {
        ComProjectGroup model = this.entityById(id);
        ComProjectGroupDTO dto = convert2DTO(model);
        dto.setExpertList(comProjectGroupAssignService.getAssignExpertList(dto.getId()));
        return dto;
    }

    @Transactional
    public String save(ComProjectGroupDTO group) {
        if (null == group.getId()) {
            return insertGroup(group);
        } else {
            return updateGroup(group);
        }
    }

    public String insertGroup(ComProjectGroupDTO group) {
        ComProjectGroup model = this.convert2Entity(group);
        return this.insert(model);
    }

    public String updateGroup(ComProjectGroupDTO group) {
        ComProjectGroup model = this.convert2Entity(group);
        return this.update(model);
    }

    public String deleteByGroupId(String id) {
        this.deleteById(id);
        return id;
    }

    private List<ComProjectAssignDTO> getAssignExpertList(String projectId) {
        return comProjectGroupDAO.getAssignExpertList(projectId);
    }

    @Transactional
    public String assignProjectGroup(int systemType, List<String> GroupList, List<String> ExpertList) {
        GroupList.forEach(g -> {
            ExpertList.forEach(e -> {
                ComProjectGroupAssign entity = new ComProjectGroupAssign();
                entity.setGroupId(g);
                entity.setExpertId(e);
                if (null == comProjectGroupAssignService.getEntity(entity)) {
                    entity = new ComProjectGroupAssign();
                    entity.setGroupId(g);
                    entity.setExpertId(e);
                    comProjectGroupAssignService.insert(entity);
                }
            });
        });

        List<ComProjectGroupDetailDTO> ProjectInfoList = comProjectGroupDetailService.getProjectListByGroupIds(GroupList);
        Integer reportYear = comBatchService.getReportYear(systemType, null);
        List<String> ProjectList = new ArrayList<>();
        ProjectInfoList.forEach(p -> {
            ProjectList.add(p.getProjId());
        });

        String strContent = comProjectAssignService.assignProject(reportYear, ProjectList, ExpertList);

        GroupList.forEach(g -> {
            this.CalculateGroupExpertCount(g);
        });

        return strContent;
    }

    @Transactional
    public String deleteAssignGroupExpert(String id) {
        ComProjectGroupAssign comProjectGroupAssign = comProjectGroupAssignService.getById(id);
        if (null == comProjectGroupAssign)
            throw new BusinessException("分配记录已删除！");

        List<ComProjectGroupDetailDTO> projectDetailList = comProjectGroupDetailService.getProjectDetailList(comProjectGroupAssign.getGroupId());
        projectDetailList.forEach(e -> {
            ComProjectAssign entity = new ComProjectAssign();
            entity.setProjId(e.getProjId());
            entity.setExpertId(comProjectGroupAssign.getExpertId());
            comProjectAssignService.delete(entity);
            comProjectAssignService.updateAssignState(e.getProjId());
        });

        List<ComProjectGroupDTO> list = comProjectAssignService.getProjectGroupAssignById(comProjectGroupAssign.getGroupId(), comProjectGroupAssign.getExpertId());
        if (null != list && list.size() > 0) {
            list.forEach(e -> {
                this.deleteById(e.getAssignId());
            });
        }
        comProjectGroupAssignService.deleteById(id);
        this.CalculateGroupExpertCount(comProjectGroupAssign.getGroupId());

        return id;
    }

    @Transactional
    public boolean deleteProjectGroupKnowledge(String groupId, String knowledgeId) {
        ComProjectGroupDTO dto = getGroupById(groupId);
        if (null == dto)
            return false;

        List<ComProjectGroupAssignDTO> expertDetailList = comProjectGroupAssignService.getAssignExpertList(groupId);
        //判断是否分配了专家(分配了专家的项目组不能移除项目)
        if (null != expertDetailList && expertDetailList.size() > 0)
            return false;

        List<ComProjectGroupDetailDTO> projectDetailList = comProjectGroupDetailService.getProjectDetailList(groupId);
        projectDetailList.forEach(e -> {
            if (e.getKnowledgeId().equals(knowledgeId))
                comProjectGroupDetailService.deleteById(e.getId());
        });

        this.CalculateGroupProjectCount(groupId);

        return true;
    }

    @Transactional
    public boolean deleteProjectGroupDetail(String groupId, String knowledgeId) {
        ComProjectGroupDTO dto = getGroupById(groupId);
        if (null == dto)
            return false;

        List<ComProjectGroupAssignDTO> expertDetailList = comProjectGroupAssignService.getAssignExpertList(groupId);
        //判断是否分配了专家(分配了专家的项目组不能移除项目)
        if (null != expertDetailList && expertDetailList.size() > 0)
            return false;

        List<ComProjectGroupDetailDTO> projectDetailList = comProjectGroupDetailService.getProjectDetailList2(groupId);
        projectDetailList.forEach(e -> {
            if (e.getKnowledgeId().equals(knowledgeId))
                comProjectGroupDetailService.deleteById(e.getId());
        });

        this.CalculateGroupProjectCount(groupId);

        return true;
    }

    @Transactional
    public boolean deleteGroupProjectExpert(String groupId, String projId) {
        ComProjectGroupDTO dto = getGroupById(groupId);
        if (null == dto)
            return false;

        List<ComProjectGroupDetailDTO> projectDetailList = comProjectGroupDetailService.getProjectDetailList(groupId);
        List<ComProjectGroupAssignDTO> expertDetailList = comProjectGroupAssignService.getAssignExpertList(groupId);

        if (null == projectDetailList || projectDetailList.size() == 0)
            return false;

        //判断是否分配了专家(分配了专家的项目不能移除)
        if (null != expertDetailList && expertDetailList.size() > 0)
            return false;

        projectDetailList.forEach(e -> {
            if (e.getGroupId().equals(groupId) && e.getProjId().equals(projId)) {
                comProjectGroupDetailService.deleteById(e.getId());
                comProjectAssignService.updateAssignState(projId);
            }
        });

        expertDetailList.forEach(e -> {
            ComProjectAssign entity = new ComProjectAssign();
            entity.setExpertId(e.getExpertId());
            entity.setProjId(projId);
            comProjectAssignService.delete(entity);
        });

        this.CalculateGroupProjectCount(groupId);
        this.CalculateGroupExpertCount(groupId);
        return true;
    }

    /**
     * 项目专家分配
     *
     * @param groupId
     * @return
     */
    @Transactional
    public void processGroupProjectExpert(String groupId) {
        ComProjectGroupDTO dto = getGroupById(groupId);
        if (null == dto)
            return;

        List<ComProjectGroupDetailDTO> projectDetailList = comProjectGroupDetailService.getProjectDetailList(groupId);
        List<ComProjectGroupAssignDTO> expertDetailList = comProjectGroupAssignService.getAssignExpertList(groupId);

        if (null == projectDetailList || projectDetailList.size() == 0)
            return;

        if (null == expertDetailList || expertDetailList.size() == 0)
            return;

        projectDetailList.forEach(e -> {
            expertDetailList.forEach(p -> {
                ComProjectAssign entity = new ComProjectAssign();
                entity.setProjId(e.getProjId());
                entity.setExpertId(p.getExpertId());
                List<ComProjectAssign> list = comProjectAssignService.entityList(entity);
                if (null == list || list.size() == 0) {
                    ComProjectAssign assign = new ComProjectAssign();
                    assign.setProjId(e.getProjId());
                    assign.setExpertId(p.getExpertId());
                    assign.setAssignYear(dto.getGroupYear());
                    comProjectAssignService.insert(assign);
                    comProjectAssignService.updateAssignState(e.getProjId());
                }
            });
        });
    }

    /**
     * 项目二级学科统计
     *
     * @param groupId
     * @return
     */
    public List<ComProjectKnowledgeStatisticDTO> getProjectKnowledgeStatisticByGroupId(String groupId) {
        List<ComProjectKnowledgeStatisticDTO> list = comProjectGroupDAO.getProjectKnowledgeStatisticByGroupId(groupId);
        return list;
    }

    @Transactional
    public Map<String, Object> getGroupProjectInfo(List<String> groupIds) {
        List<ComProjectGroupDetailDTO> project = comProjectGroupDetailService.getProjectListByGroupIds(groupIds);
        List<String> expanded = new ArrayList<>();
        List<String> specs = new ArrayList<>();
        project.forEach(e -> {
            if (!expanded.contains(e.getPpkey()))
                expanded.add(e.getPpkey());
            if (!expanded.contains(e.getPkey()))
                expanded.add(e.getPkey());
            if (!specs.contains(e.getKnowledgeId()))
                specs.add(e.getKnowledgeId());
        });
        Map<String, Object> projInfo = new HashMap<String, Object>(4) {
            {
                put("expanded", expanded);
                put("spec", specs);
            }
        };
        return projInfo;
    }
}
