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.ComProjectAssignDAO;
import com.yiboshi.science.entity.AssignCount;
import com.yiboshi.science.entity.ComProject;
import com.yiboshi.science.entity.ComProjectAssign;
import com.yiboshi.science.enumeration.CommonEnum;
import com.yiboshi.science.param.dto.ComProjectAssignDTO;
import com.yiboshi.science.param.dto.ComProjectGroupDTO;
import com.yiboshi.science.param.query.ComProjectAssignQueryVO;
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.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

@Service
@AllArgsConstructor
public class ComProjectAssignServiceImpl extends BaseServiceImpl<ComProjectAssignDAO, ComProjectAssignQueryVO, ComProjectAssignDTO, ComProjectAssign> implements ComProjectAssignService {
    @Autowired
    private ComProjectAssignDAO comProjectAssignDAO;
    @Autowired
    private ComBatchService comBatchService;
    @Autowired
    private ComExpertSpecService comExpertSpecService;

    @Override
    protected void setCriteriaForQuery(ComProjectAssignQueryVO vo, QueryWrapper<ComProjectAssignQueryVO> criteria) {
        if (Objects.nonNull(vo.getExpertId())) {
            criteria.eq("a.expert_id", vo.getExpertId());
        }
        if (Objects.nonNull(vo.getProjId())) {
            criteria.eq("a.proj_id", vo.getProjId());
        }
        if (Objects.nonNull(vo.getAssignYear())) {
            criteria.eq("assign_year", vo.getAssignYear());
        }
        if (Objects.nonNull(vo.getTotalScore())) {
            criteria.eq("total_score", vo.getTotalScore());
        }
        if (Objects.nonNull(vo.getCertId())) {
            criteria.like("c.cert_id", vo.getCertId());
        }
        if (Objects.nonNull(vo.getPersonName())) {
            criteria.like("c.person_name", vo.getPersonName());
        }
        if (Objects.nonNull(vo.getSex())) {
            criteria.eq("c.sex", vo.getSex());
        }
        if (Objects.nonNull(vo.getProjName())) {
            criteria.like("f.proj_name", vo.getProjName());
        }
        if (Objects.nonNull(vo.getProjType())) {
            criteria.eq("f.proj_type", vo.getProjType());
        }
        if (Objects.nonNull(vo.getProjNo())) {
            criteria.like("f.proj_no", vo.getProjNo());
        }
    }

    @Override
    public Pagination<ComProjectAssignDTO> getListByPage(ComProjectAssignQueryVO vo) {
        QueryWrapper criteria = new QueryWrapper();
        setCriteriaForQuery(vo, criteria);
        Page<ComProjectAssignQueryVO> page = new Page<>(vo.getPageIndex(), vo.getPageSize());
        List<ComProjectAssignDTO> dtoList = comProjectAssignDAO.getListByPage(page, criteria).getRecords();
        return new Pagination<>(dtoList, page.getTotal(), vo.getPageSize());
    }

    @Transactional
    public String assignProject(Map<String, Object> map) {
        List<String> projects = null;
        List<String> experts = null;
        if (!map.containsKey("type"))
            throw new BusinessException("参数错误");
        if (!map.containsKey("projects"))
            throw new BusinessException("参数错误");
        if (!map.containsKey("projType"))
            throw new BusinessException("参数错误");
        Integer projType = CommonEnum.projType.num.getCode();
        if (map.containsKey("projType")) {
            projType = (int) map.get("projType");
        }
        experts = (List<String>) map.get("experts");
        projects = (List<String>) map.get("projects");
        Integer reportYear = comBatchService.getReportYear(projType);
        if (null == projects || projects.size() == 0 || null == experts || experts.size() == 0)
            throw new BusinessException("参数错误");
        return this.assignProject(reportYear, projects, experts);
    }

    public String assignProject(Integer year, List<String> projects, List<String> experts) {
        AtomicInteger allCount = new AtomicInteger(0);
        projects.forEach(e -> {
            AtomicInteger assignCount = new AtomicInteger(0);
            experts.forEach(f -> {
                if (!isDistribute(e, f)) {
                    ComProjectAssign assign = new ComProjectAssign();
                    assign.setProjId(e);
                    assign.setExpertId(f);
                    assign.setAssignYear(year);
                    this.insert(assign);
                    assignCount.incrementAndGet();
                    allCount.incrementAndGet();
                }
            });
            if (assignCount.get() > 0)
                updateAssignState(e);
        });
        if (allCount.get() == 0)
            throw new BusinessException("项目分配失败或专家已分配，请检查！");
        return allCount.getAndIncrement() + "";
    }

    public String deleteAssignExpert(String id) {
        ComProjectAssign comProjectAssign = this.getById(id);
        if (null == comProjectAssign)
            throw new BusinessException("分配记录已删除！");
        if (Objects.nonNull(comProjectAssign.getAuditState()) || !comProjectAssign.getAuditState().equals(0))
            throw new BusinessException("专家已评审，不允许删除！");
        this.deleteById(id);
        this.updateAssignState(comProjectAssign.getProjId());
        return id;
    }

    @Transactional
    public String expertEvaluation(ComProjectAssignDTO dto) {
        ComProjectAssign comProjectAssign = this.getById(dto.getId());
        if (null == comProjectAssign)
            throw new BusinessException("分配记录不存在或已删除！");
        ComProjectAssign entity = convert2Entity(dto);
        this.update(entity);
        if (Objects.nonNull(dto.getAuditState()) && dto.getAuditState().equals(2)) {
            this.updateAssignState(entity.getProjId());
        }
        return entity.getId();
    }

    public ComProjectAssignDTO getAssignExpertById(String id) {
        ComProjectAssignDTO dto = comProjectAssignDAO.getAssignExpertById(id);
        if (null != dto) {
            dto.setSpecList(comExpertSpecService.getListByExpertId(dto.getExpertId()));
        }
        return dto;
    }

    public List<AssignCount> getAssignCount(String expertId) {
        return comProjectAssignDAO.getAssignCount(expertId);
    }

    public List<ComProjectAssignDTO> getAssignExpertList(String projectId) {
        return comProjectAssignDAO.getAssignExpertList(projectId);
    }

    private boolean isDistribute(String projectId, String expertId) {
        ComProjectAssign comProjectAssign = new ComProjectAssign();
        comProjectAssign.setProjId(projectId);
        comProjectAssign.setExpertId(expertId);
        comProjectAssign = this.getEntity(comProjectAssign);
        if (comProjectAssign != null)
            return true;
        else
            return false;
    }

    public void updateAssignState(String projectId) {
        Integer assignState;
        Integer completed;
        BigDecimal totalScore = new BigDecimal(0);
        BigDecimal averageScore = new BigDecimal(0);
        List<ComProjectAssignDTO> list = this.getAssignExpertList(projectId);
        if (null == list || list.size() == 0) {
            completed = 0;
            assignState = 0;
        } else {
            int scoreCount = 0;
            for (ComProjectAssignDTO obj : list) {
                if (Objects.nonNull(obj.getTotalScore()) && Objects.nonNull(obj.getAuditState()) && obj.getAuditState().equals(2)) {
                    scoreCount++;
                    totalScore = totalScore.add(obj.getTotalScore());
                }
            }
            if (scoreCount > 0) {
                DecimalFormat df1 = new DecimalFormat("0.00");
                averageScore = totalScore.divide(new BigDecimal(scoreCount),2,BigDecimal.ROUND_HALF_UP);
                totalScore = new BigDecimal(df1.format(totalScore));
            }
            if (list.size() > scoreCount)
                completed = 0;
            else
                completed = 1;
            assignState = 1;
        }
        this.updateAssignState(projectId, assignState, completed, totalScore, averageScore);
    }

    public void updateAssignState(String projectId, Integer assignState, Integer completed, BigDecimal totalScore, BigDecimal averageScore) {
        ComProject comProject = new ComProject();
        comProject.setId(projectId);
        comProject.setAssignState(assignState);
        comProject.setCompleted(completed);
        comProject.setTotalScore(totalScore);
        comProject.setAverageScore(averageScore);
        comProject.setUpdated(new Date());
        comProjectAssignDAO.updateAssignState(comProject);
    }

    public List<ComProjectGroupDTO> getProjectGroupAssignById(String id, String expertId) {
        return comProjectAssignDAO.getProjectGroupAssignById(id, expertId);
    }
}
