package com.yiboshi.science.service.impl;

import com.alibaba.excel.util.StringUtils;
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.config.bean.SystemProperties;
import com.yiboshi.science.dao.ComProjectDAO;
import com.yiboshi.science.dao.ComProjectTaskDAO;
import com.yiboshi.science.entity.*;
import com.yiboshi.science.enumeration.CommonEnum;
import com.yiboshi.science.param.dto.*;
import com.yiboshi.science.param.query.ComProjectTaskQueryVO;
import com.yiboshi.science.service.*;
import com.yiboshi.science.utils.DateUtils;
import com.yiboshi.science.utils.ExcelUtils;
import com.yiboshi.science.utils.HtmlBuilder;
import com.yiboshi.science.utils.SystemSetKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 任务书表 Service 实现类
 *
 * @author lkl
 * @version 2021-08-26
 */
@Service
public class ComProjectTaskServiceImpl extends BaseServiceImpl<ComProjectTaskDAO, ComProjectTaskQueryVO, ComProjectTaskDTO, ComProjectTask> implements ComProjectTaskService {
    @Autowired
    private ComProjectTaskDAO ComProjectTaskDAO;
    @Autowired
    private ComProjectMembersService comProjectMembersService;
    @Autowired
    private ComProjectBudgetService comProjectBudgetService;
    @Autowired
    private ComPersonService comPersonService;
    @Autowired
    private ComUnitService comUnitService;
    @Autowired
    private ComProjectCooperativeUnitsService comProjectCooperativeUnitsService;
    @Autowired
    private ComProjectAuditService comProjectAuditService;
    @Autowired
    private ComProjectStageGoalService comProjectStageGoalService;
    @Autowired
    private ComProjectEquipmentService comProjectEquipmentService;
    @Autowired
    private ComProjectManufactureService comProjectManufactureService;
    @Autowired
    private ComProjectSubService comProjectSubService;
    @Autowired
    private ComProjectFundPlanService comProjectFundPlanService;
    @Autowired
    private ComProjectKpitDetailService comProjectKpitDetailService;
    @Autowired
    private  ComProjectUnitPaymentService comProjectUnitPaymentService;
    @Autowired
    private ComFileService ComFileService;
    @Autowired
    private ComProjectKpitService comProjectKpitService;
    @Autowired
    private SystemParameterService systemParameterService;

    @Override
    protected void setCriteriaForQuery(ComProjectTaskQueryVO vo, QueryWrapper<ComProjectTaskQueryVO> criteria) {
        if (Objects.nonNull(vo.getProjId())) {
            criteria.eq("proj_id", vo.getProjId());
        }
        if (Objects.nonNull(vo.getReportYear())) {
            criteria.eq("c.report_year", vo.getReportYear());
        }
        if (Objects.nonNull(vo.getProjType())) {
            criteria.eq("proj_type", vo.getProjType());
        }
        if (Objects.nonNull(vo.getAppUnitId())) {
            criteria.eq("app_unit_id", vo.getAppUnitId());
        }
        if (Objects.nonNull(vo.getAppPersonId())) {
            criteria.eq("app_person_id", vo.getAppPersonId());
        }
        if (Objects.nonNull(vo.getStartDate())) {
            criteria.eq("start_date", vo.getStartDate());
        }
        if (Objects.nonNull(vo.getEndDate())) {
            criteria.eq("end_date", vo.getEndDate());
        }
        if (Objects.nonNull(vo.getProjState())) {
            criteria.eq("proj_state", vo.getProjState());
        }
        if (Objects.nonNull(vo.getProjName())) {
            criteria.like("proj_name", vo.getProjName());
        }
        if (Objects.nonNull(vo.getProjNo())) {
            criteria.like("proj_no", vo.getProjNo());
        }
        if (Objects.nonNull(vo.getAppUnitName())) {
            criteria.like("unit_name", vo.getAppUnitName());
        }
        if (Objects.nonNull(vo.getAppPersonName())) {
            criteria.like("person_name", vo.getAppPersonName());
        }
        if (Objects.nonNull(vo.getTaskState())) {
            switch (vo.getTaskState()) {
                case 1://未上报任务书
                    criteria.and(qw -> qw.in("task_state", CommonEnum.taskState.draft.getCode(),
                            CommonEnum.taskState.waitSubmit.getCode()).or().isNull("task_state"));
                    break;
                case 2://返回修改任务书
                    criteria.eq("task_state", CommonEnum.taskState.returnModify.getCode());
                    break;
                case 3://已上报任务书
                    criteria.in("task_state",
                            CommonEnum.taskState.review.getCode(),
                            CommonEnum.taskState.failed.getCode(),
                            CommonEnum.taskState.pass.getCode());
                    break;
                case 4://所有任务书
                    break;
                case 5://任务书
                    criteria.and(qw -> qw.in("task_state", CommonEnum.taskState.review.getCode()).or().isNull("test_state"));
                    break;
            }
        }
    }

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

    public DataStatisticsDTO getCount(ComProjectTaskQueryVO e) {
        QueryWrapper criteria = new QueryWrapper();
        setCriteriaForQuery(e, criteria);
        return ComProjectTaskDAO.getCount(criteria);
    }

    public void updateState(String id, Integer state) {
        ComProjectTask ComProjectTask = new ComProjectTask();
        ComProjectTask.setId(id);
        ComProjectTask.setTaskState(state);
        this.update(ComProjectTask);
    }

    public ComProjectTaskDTO getTaskByProjId(String projId) {
        ComProjectTaskDTO dto = ComProjectTaskDAO.getByProjId(projId);
        //申报单位
        ComUnitDTO comUnitDTO = comUnitService.getUnitById(dto.getAppUnitId());
        if (null != comUnitDTO) {
            dto.setAppUnitName(comUnitDTO.getUnitName());
            if (Objects.isNull(dto.getOrganizationCode()))
                dto.setOrganizationCode(comUnitDTO.getOrganizationCode());
            if (Objects.isNull(dto.getUnitAddress()))
                dto.setUnitAddress(comUnitDTO.getUnitAddress());
            if (Objects.isNull(dto.getRegisteredAddress()))
                dto.setRegisteredAddress(comUnitDTO.getRegisteredAddress());
            if (Objects.isNull(dto.getPostCode()))
                dto.setPostCode(comUnitDTO.getPostCode());

            if (Objects.isNull(dto.getLegalPerson()))
                dto.setLegalPerson(comUnitDTO.getLegalPerson());
            if (Objects.isNull(dto.getWorkforce()))
                dto.setWorkforce(comUnitDTO.getWorkforce());
            if (Objects.isNull(dto.getSpecializedPersonnel()))
                dto.setSpecializedPersonnel(comUnitDTO.getSpecializedPersonnel());
            if (Objects.isNull(dto.getResearchPersonnel()))
                dto.setResearchPersonnel(comUnitDTO.getResearchPersonnel());

            if (Objects.isNull(dto.getDepositBank()))
                dto.setDepositBank(comUnitDTO.getDepositBank());
            if (Objects.isNull(dto.getBankAccount()))
                dto.setBankAccount(comUnitDTO.getBankAccount());
            if (Objects.isNull(dto.getDepositBankAddress()))
                dto.setDepositBankAddress(comUnitDTO.getDepositBankAddress());
            if (Objects.isNull(dto.getInterbankNumber()))
                dto.setInterbankNumber(comUnitDTO.getInterbankNumber());
        }
        // 申报人
        ComPersonDTO comPersonDTO = comPersonService.getPersonById(dto.getAppPersonId());
        if (null != comPersonDTO) {
            dto.setAppPersonName(comPersonDTO.getPersonName());
            dto.setCertId(comPersonDTO.getCertId());
            dto.setSex(comPersonDTO.getSex());
            dto.setBirthday(comPersonDTO.getBirthday());
            dto.setNationName(comPersonDTO.getNationName());
            dto.setDegreeName(comPersonDTO.getDegreeName());
            dto.setTitleName(comPersonDTO.getTitleName());
            dto.setDutyName(comPersonDTO.getDuty());
            dto.setSpecName(comPersonDTO.getSpecName());
            dto.setMobile(comPersonDTO.getMobile());
            dto.setEmail(comPersonDTO.getEmail());
        }
        //获取项目组成员
        List<ComProjectMembersDTO> memList = comProjectMembersService.getListByObjectId(dto.getProjId());
        dto.setMembers(memList);

        ComProjectMembersDTO comProjectMembersDTO = comProjectMembersService.getMemCountById(dto.getProjId());
        dto.setMemCount(comProjectMembersDTO.getMemCount() + 1);
        dto.setMemHighCount(comProjectMembersDTO.getMemHighCount());
        dto.setMemMiddleCount(comProjectMembersDTO.getMemMiddleCount());
        dto.setMemLowCount(comProjectMembersDTO.getMemLowCount());
        dto.setMemBshCount(comProjectMembersDTO.getMemBshCount());
        dto.setMemBsCount(comProjectMembersDTO.getMemBsCount());
        dto.setMemSsCount(comProjectMembersDTO.getMemSsCount());
        dto.setMemXsCount(comProjectMembersDTO.getMemXsCount());
        dto.setWorkCount(comProjectMembersDTO.getWorkCount());

        //申报人职称统计
        if (!StringUtils.isEmpty(comPersonDTO.getTitle())) {
            String titleName = systemParameterService.judgmentTitleLevel(comPersonDTO.getTitle());
            if (!StringUtils.isEmpty(titleName)) {
                switch (titleName) {
                    case "无职称":
                    case "初级职称":
                        dto.setMemLowCount(dto.getMemLowCount() + 1);
                        break;
                    case "中级职称":
                        dto.setMemMiddleCount(dto.getMemMiddleCount() + 1);
                        break;
                    case "副高级职称":
                    case "高级职称":
                        dto.setMemHighCount(dto.getMemHighCount() + 1);
                        break;
                }
            }
        }

//        // 项目合作单位
//        List<ComProjectCooperativeUnitsDTO> cooperativeUnits = comProjectCooperativeUnitsService.getListByObjectId(dto.getProjId(), 1);
//        dto.setCooperativeUnits(cooperativeUnits);

        // 项目参与单位
        List<ComProjectCooperativeUnitsDTO> participateUnits = comProjectCooperativeUnitsService.getListByObjectId(dto.getProjId(), 2);
        dto.setParticipateUnits(participateUnits);

        //经费表
        List<ComProjectBudgetDTO> budgetList = comProjectBudgetService.getListByObjectId(dto.getProjId());
        dto.setBudget(budgetList);

        // 年度用款计划
        List<ComProjectFundPlanDTO> fundPlanList = comProjectFundPlanService.getListByObjectId(dto.getProjId());
        if (null == fundPlanList || fundPlanList.size() == 0)
            fundPlanList = comProjectFundPlanService.getList();
        dto.setFundPlan(fundPlanList);

        // 购置设备预算明细表
        List<ComProjectEquipmentDTO> equipmentList = comProjectEquipmentService.getListByObjectId(dto.getProjId());
        dto.setDeviceList(equipmentList);

        // 试制设备预算明细表
        List<ComProjectManufactureDTO> manufactureList = comProjectManufactureService.getListByObjectId(dto.getProjId());
        dto.setManufactureList(manufactureList);

        // 单位支出明细预算
        List<ComProjectUnitPaymentDTO> unitPaymentList = comProjectUnitPaymentService.getListByObjectId(dto.getProjId());
        dto.setUnitPayment(unitPaymentList);

        // 项目绩效目标表
        LoadProjectKPIInfo(dto);

        // 项目安排及阶段目标
        List<ComProjectStageGoalDTO> stageGoals = comProjectStageGoalService.getListByObjectId(dto.getProjId());
        dto.setStageGoals(stageGoals);

        // 项目课颖设置表
        List<ComProjectSubDTO> projectSubList = comProjectSubService.getListByObjectId(dto.getProjId());
        dto.setProjectSubList(projectSubList);

//        // 在研或完成基础研究项目情况
//        List<ComProjectResearchDTO> projectResearchList = comProjectResearchService.getListByObjectId(dto.getProjId());
//        dto.setProjectResearchList(projectResearchList);

//        // 单位科研项目及资金管理制度表
//        List<ComProjectManagementRuleDTO> managementRuleList = comProjectManagementRuleService.getListByObjectId(dto.getProjId());
//        dto.setManagementRuleList(managementRuleList);

        //附件列表
        List<ComFileDTO> fileList = ComFileService.getListByObjectId(dto.getProjId(), CommonEnum.fileType.project.getCode());
        if (null == fileList || fileList.size() == 0)
            fileList = configureFileList(dto.getProjType());
        else
            fileList = checkNecessaryAttachmentFile(dto.getProjType(), fileList);
        dto.setFileList(fileList);
        return dto;

    }
    private void LoadProjectKPIInfo(ComProjectTaskDTO dto) {
        List<ComProjectKpitDTO> ProjectKPIList = comProjectKpitDetailService.getProjectKpitDetailStatistic(dto.getId());
        if (null == ProjectKPIList || ProjectKPIList.size() == 0)
            ProjectKPIList = comProjectKpitService.getProjectKpitStatistic();
        ProjectKPIStatisticDTO kpiDTO = new ProjectKPIStatisticDTO();
        kpiDTO.setTotalRowSpan(ProjectKPIList.size() + 2);
        kpiDTO.setThreeLevel(ProjectKPIList);

        kpiDTO.setReportYear(dto.getReportYear());
        kpiDTO.setProjName(dto.getProjName());
        kpiDTO.setAppUnitName(dto.getAppUnitName());
        kpiDTO.setManagerDept(dto.getManagerDept());
        kpiDTO.setProjAttribute(dto.getProjAttribute());
        kpiDTO.setYearTarget(dto.getYearTarget());
        kpiDTO.setYear1Goal(dto.getYear1Goal());
        kpiDTO.setYear2Goal(dto.getYear2Goal());
        kpiDTO.setYear3Goal(dto.getYear3Goal());
        if (Objects.nonNull(dto.getStartDate()) && Objects.nonNull(dto.getEndDate())) {
            kpiDTO.setStartDate(dto.getStartDate());
            kpiDTO.setEndDate(dto.getEndDate());
            kpiDTO.setProjDeadline(DateUtils.FormatDate(dto.getStartDate()) + "至" + DateUtils.FormatDate(dto.getEndDate()));
        }
        List<ComProjectBudgetDTO> budgetDTO = dto.getBudget();
        if (null != budgetDTO) {
            // 资金总额
            List<ComProjectBudgetDTO> FindList = budgetDTO.stream().filter(e -> e.getBudgetId().equals("3b1f57d3-6aec-4129-aef5-702a1accfe01")).collect(Collectors.toList());
            if (null != FindList)
                kpiDTO.setTotalBudget(FindList.get(0).getTotalBudget());
            // 省级财政资金
            FindList = budgetDTO.stream().filter(e -> e.getBudgetId().equals("3b1f57d3-6aec-4129-aef5-702a1accfe02")).collect(Collectors.toList());
            if (null != FindList)
                kpiDTO.setApplyFunds(FindList.get(0).getTotalBudget());
            // 自筹资金
            FindList = budgetDTO.stream().filter(e -> e.getBudgetId().equals("3b1f57d3-6aec-4129-aef5-702a1accfe03")).collect(Collectors.toList());
            if (null != FindList)
                kpiDTO.setSelfFunds(FindList.get(0).getTotalBudget());
        } else {
            kpiDTO.setTotalBudget(new BigDecimal(0.00));
            kpiDTO.setApplyFunds(new BigDecimal(0.00));
            kpiDTO.setSelfFunds(new BigDecimal(0.00));
        }

        List<ComProjectFundPlanDTO> fundPlanDTO = dto.getFundPlan();
        if (null != fundPlanDTO) {
            List<ComProjectFundPlanDTO> FindList = fundPlanDTO.stream().filter(e -> e.getFundId().equals("6a18820d-ad2b-11ef-b6cb-0c42a1380f01")).collect(Collectors.toList());
            if (null != FindList)
                kpiDTO.setYearTotal(FindList.get(0).getYearValue1());
            FindList = fundPlanDTO.stream().filter(e -> e.getFundId().equals("6a18820d-ad2b-11ef-b6cb-0c42a1380f02")).collect(Collectors.toList());
            if (null != FindList)
                kpiDTO.setYearApply(FindList.get(0).getYearValue1());
            FindList = fundPlanDTO.stream().filter(e -> e.getFundId().equals("6a18820d-ad2b-11ef-b6cb-0c42a1380f03")).collect(Collectors.toList());
            if (null != FindList)
                kpiDTO.setYearSelf(FindList.get(0).getYearValue1());
        } else {
            kpiDTO.setYearTotal(new BigDecimal(0.00));
            kpiDTO.setYearApply(new BigDecimal(0.00));
            kpiDTO.setYearSelf(new BigDecimal(0.00));
        }

        dto.setProjectKPI(kpiDTO);
    }

    private List<ComFileDTO> configureFileList(Integer projType) {
        List<ComFileDTO> fileList = new ArrayList<>();
        List<SystemParameter> parameterList;
        //健康领域科技项目
        if (projType == CommonEnum.projType.num.getCode())
            parameterList = systemParameterService.getListByType(61);
        else//临床科技项目
            parameterList = systemParameterService.getListByType(13);
        parameterList.forEach(e -> {
            fileList.add(configureFile(e.getName(), e.getDisplayOrder(), e.getIsRequired()));
        });
        return fileList;
    }

    private ComFileDTO configureFile(String FileExplain, int showIndex, Boolean isRequired) {
        ComFileDTO file = new ComFileDTO();
        file.setFileType(CommonEnum.fileType.project.getCode());
        file.setFileExplain(FileExplain);
        file.setShowIndex(showIndex);
        file.setRequired(true);
        if (!isRequired.equals(null))
            file.setIsRequired(isRequired);
        else
            file.setIsRequired(false);
        return file;
    }

    public List<ComFileDTO> checkNecessaryAttachmentFile(Integer projType, List<ComFileDTO> fileList) {
        List<SystemParameter> parameterList;
        //健康领域科技项目
        if (projType == CommonEnum.projType.num.getCode())
            parameterList = systemParameterService.getListByType(61);
        else//临床科技项目
            parameterList = systemParameterService.getListByType(13);

        AtomicInteger allCount = new AtomicInteger(parameterList.size() + 1);
        fileList.forEach(e -> {
            AtomicInteger num = new AtomicInteger(1);
            int i = num.get();
            parameterList.forEach(p -> {
                if (null != e.getFileExplain() && e.getFileExplain().equals(p.getName())) {
                    e.setShowIndex(p.getDisplayOrder());
                    e.setRequired(true);
                    num.incrementAndGet();
                }
            });
            if (i == num.get()) {
                e.setShowIndex(allCount.get());
                e.setRequired(false);
                allCount.incrementAndGet();
            }
        });

        parameterList.forEach(p -> {
            List<ComFileDTO> findList = fileList.stream().filter(e -> null != e.getFileExplain() && e.getFileExplain().equals(p.getName())).collect(Collectors.toList());
            if (findList.size() == 0) {
                ComFileDTO fileDTO = configureFile(p.getName(), p.getDisplayOrder(), p.getIsRequired());
                fileList.add(fileDTO);
            }
        });

        fileList.sort(Comparator.comparingInt(ComFileDTO::getShowIndex));

        return fileList;
    }

    @Transactional
    public String save(ComProjectTaskDTO dto) {
        if (dto.getTaskState().equals(CommonEnum.taskState.noWrite.getCode()))
            dto.setTaskState(CommonEnum.taskState.draft.getCode());
        String id = "";
        ComProjectTask task = new ComProjectTask();
        task.setProjId(dto.getProjId());
        task = this.getEntity(task);
        if (null == task) {
            task = convert2Entity(dto);
            id = this.insert(task);
        } else {
            task = convert2Entity(dto);
            id = this.update(task);
        }
        return id;
    }

    @Transactional
    public void report(ComProjectAudit model, String unitId, String treeCode) {
        ComProjectTask ComProjectTask = this.entityById(model.getAuditObjectId());
        if (null == ComProjectTask)
            throw new BusinessException("合同书不存在！");
        if (!ComProjectTask.getTaskState().equals(CommonEnum.taskState.waitSubmit.getCode()) && !ComProjectTask.getTaskState().equals(CommonEnum.taskState.returnModify.getCode()))
            throw new BusinessException("合同书已上报");
        comProjectAuditService.report(ComProjectTask.getReportYear(), model.getAuditObjectId(), model.getAuditType(), unitId, treeCode);
        // 更新任务书状态
        this.updateState(model.getAuditObjectId(), CommonEnum.taskState.review.getCode());
    }

    @Transactional
    public void audit(ComProjectAudit dto, String auditUnitId, String treeCode) {
        // false 报上级或返回下一级  true报到最高级或返回个人
        int state = 0;
        ComProjectTask task = this.getById(dto.getAuditObjectId());
        if (null == task)
            throw new BusinessException("审核对象不存在！");
        ComProjectTaskDTO dt = this.getTaskByProjId(task.getProjId());
        ComUnit appUnit = comUnitService.getById(dt.getAppUnitId());
        if (null == appUnit)
            throw new BusinessException("申报单位不存在,或已删除！");
        ComProjectAudit audit = comProjectAuditService.getById(dto.getId());
        audit.setAuditResult(dto.getAuditResult());
        audit.setAuditContent(dto.getAuditContent());
        //  返回上级或下级单位Id, 最高级或个人返回 null
        String unitId = comProjectAuditService.audit(audit, appUnit.getTreeCode(), treeCode);
        // 处理项目状态
        Integer taskState = null;
        if (audit.getAuditResult().equals(CommonEnum.auditResult.pass.getCode())) {
            if (unitId == null) {
                taskState = CommonEnum.taskState.pass.getCode();
            }
        } else if (audit.getAuditResult().equals(CommonEnum.auditResult.returnModify.getCode())) {
            if (unitId == null)
                taskState = CommonEnum.taskState.returnModify.getCode();
        } else {
            taskState = CommonEnum.taskState.failed.getCode();
        }
        if (null != taskState)
            this.updateState(dto.getAuditObjectId(),taskState);
    }
}