package ink.wgink.module.activiti.service.oa.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.module.activiti.dao.oa.IOaOnFileDao;
import ink.wgink.module.activiti.pojo.dtos.oa.OaOnFileDTO;
import ink.wgink.module.activiti.pojo.pos.oa.OaOnFilePO;
import ink.wgink.module.activiti.pojo.vos.oa.OaOnFileVO;
import ink.wgink.module.activiti.service.oa.IOaFormReportService;
import ink.wgink.module.activiti.service.oa.IOaOnFileService;
import ink.wgink.module.form.service.design.IFormDesignService;
import ink.wgink.pojo.ListPage;
import ink.wgink.pojo.result.SuccessResultList;
import ink.wgink.util.ArrayListUtil;
import ink.wgink.util.UUIDUtil;
import ink.wgink.util.date.DateUtil;
import ink.wgink.util.map.HashMapUtil;
import org.activiti.engine.HistoryService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * @ClassName: OaOnFileServiceImpl
 * @Description: OA归档
 * @Author: wanggeng
 * @Date: 2022/5/13 09:58
 * @Version: 1.0
 */
@Service
public class OaOnFileServiceImpl extends DefaultBaseService implements IOaOnFileService {

    @Autowired
    private IOaOnFileDao oaOnFileDao;
    @Autowired
    private HistoryService historyService;

    @Override
    public void save(OaOnFileVO oaOnFileVO) {
        saveAndReturnId(oaOnFileVO);
    }

    @Override
    public String saveAndReturnId(OaOnFileVO oaOnFileVO) {
        String onFileId = UUIDUtil.getUUID();
        Map<String, Object> params = HashMapUtil.beanToMap(oaOnFileVO);
        params.put("onFileId", onFileId);
        setSaveInfo(params);
        oaOnFileDao.save(params);
        return onFileId;
    }

    @Override
    public void remove(List<String> ids) {
        Map<String, Object> params = getHashMap(2);
        params.put("onFileIds", ids);
        setUpdateInfo(params);
        oaOnFileDao.remove(params);
    }

    @Override
    public void delete(List<String> ids) {
        Map<String, Object> params = getHashMap(2);
        params.put("onFileIds", ids);
        oaOnFileDao.delete(params);
    }

    @Override
    public OaOnFileDTO get(Map<String, Object> params) {
        params = params == null ? getHashMap(0) : params;
        return oaOnFileDao.get(params);
    }

    @Override
    public OaOnFileDTO getById(String onFileId) {
        Map<String, Object> params = getHashMap(2);
        params.put("onFileId", onFileId);
        return get(params);
    }

    @Override
    public OaOnFileDTO getByProcessInstanceId(String processInstanceId) {
        Map<String, Object> params = getHashMap(2);
        params.put(IFormDesignService.PARAM_PROCESS_INSTANCE_ID, processInstanceId);
        return get(params);
    }

    @Override
    public OaOnFileDTO getByReportUid(String reportUid) {
        Map<String, Object> params = getHashMap(2);
        params.put(IOaFormReportService.KEY_REPORT_UID, reportUid);
        return get(params);
    }

    @Override
    public OaOnFilePO getPO(Map<String, Object> params) {
        params = params == null ? getHashMap(0) : params;
        return oaOnFileDao.getPO(params);
    }

    @Override
    public OaOnFilePO getPOById(String onFileId) {
        Map<String, Object> params = getHashMap(2);
        params.put("onFileId", onFileId);
        return getPO(params);
    }

    @Override
    public OaOnFilePO getPOByProcessInstanceId(String processInstanceId) {
        Map<String, Object> params = getHashMap(2);
        params.put(IFormDesignService.PARAM_PROCESS_INSTANCE_ID, processInstanceId);
        return getPO(params);
    }

    @Override
    public OaOnFilePO getPOByReportUid(String reportUid) {
        Map<String, Object> params = getHashMap(2);
        params.put(IOaFormReportService.KEY_REPORT_UID, reportUid);
        return getPO(params);
    }

    @Override
    public List<OaOnFilePO> listPO(Map<String, Object> params) {
        params = params == null ? getHashMap(0) : params;
        return oaOnFileDao.listPO(params);
    }

    @Override
    public List<OaOnFilePO> listPOByIds(List<String> onFileIds) {
        if (onFileIds == null || onFileIds.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, Object> params = getHashMap(2);
        params.put("onFileIds", onFileIds);
        return listPO(params);
    }

    @Override
    public List<OaOnFilePO> listPOByFormCodeAndFormVersion(String formCode, Integer formVersion) {
        if (StringUtils.isBlank(formCode) || formVersion == null) {
            return new ArrayList<>();
        }
        Map<String, Object> params = getHashMap(4);
        params.put(IFormDesignService.PARAM_FORM_CODE, formCode);
        params.put(IFormDesignService.PARAM_FORM_VERSION, formVersion);
        return listPO(params);
    }

    @Override
    public List<OaOnFilePO> listPOByProcessInstanceIds(List<String> processInstanceIds) {
        if (processInstanceIds == null || processInstanceIds.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, Object> params = getHashMap(2);
        params.put("processInstanceIds", processInstanceIds);
        return listPO(params);
    }

    @Override
    public List<OaOnFilePO> listPOByReportUids(List<String> reportUids) {
        if (reportUids == null || reportUids.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, Object> params = getHashMap(2);
        params.put("reportUids", reportUids);
        return listPO(params);
    }

    @Override
    public List<OaOnFileDTO> list(Map<String, Object> params) {
        params = params == null ? getHashMap(0) : params;
        List<OaOnFileDTO> oaOnFileDTOs = oaOnFileDao.list(params);
        setProcessInstanceParams(oaOnFileDTOs);
        return oaOnFileDTOs;
    }

    @Override
    public List<OaOnFileDTO> listByIds(List<String> onFileIds) {
        if (onFileIds == null || onFileIds.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, Object> params = getHashMap(2);
        params.put("onFileIds", onFileIds);
        return list(params);
    }

    @Override
    public List<OaOnFileDTO> listByFormCodeAndFormVersion(String formCode, Integer formVersion) {
        if (StringUtils.isBlank(formCode) || formVersion == null) {
            return new ArrayList<>();
        }
        Map<String, Object> params = getHashMap(4);
        params.put(IFormDesignService.PARAM_FORM_CODE, formCode);
        params.put(IFormDesignService.PARAM_FORM_VERSION, formVersion);
        return list(params);
    }

    @Override
    public List<OaOnFileDTO> listByProcessInstanceIds(List<String> processInstanceIds) {
        if (processInstanceIds == null || processInstanceIds.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, Object> params = getHashMap(2);
        params.put("processInstanceIds", processInstanceIds);
        return list(params);
    }

    @Override
    public List<OaOnFileDTO> listByReportUids(List<String> reportUids) {
        if (reportUids == null || reportUids.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, Object> params = getHashMap(2);
        params.put("reportUids", reportUids);
        return list(params);
    }

    @Override
    public List<OaOnFileDTO> listUnOnFile() {
        Map<String, Object> params = getHashMap(0);
        List<String> processInstanceIds = oaOnFileDao.listUnOnFileProcessInstanceId(params);
        return listUnOnFile(new HashSet<>(processInstanceIds));
    }

    @Override
    public List<OaOnFileDTO> listUnFinishedUnOnFile() {
        Map<String, Object> params = getHashMap(2);
        params.put(KEY_UN_FINISHED, ISystemConstant.IS_TRUE);
        List<String> processInstanceIds = oaOnFileDao.listUnOnFileProcessInstanceId(params);
        return listUnFinishedUnOnFile(new HashSet<>(processInstanceIds));
    }

    @Override
    public List<OaOnFileDTO> listFinishedUnOnFile() {
        Map<String, Object> params = getHashMap(2);
        params.put(KEY_FINISHED, ISystemConstant.IS_TRUE);
        List<String> processInstanceIds = oaOnFileDao.listUnOnFileProcessInstanceId(params);
        return listFinishedUnOnFile(new HashSet<>(processInstanceIds));
    }

    @Override
    public List<OaOnFileDTO> listFinishedUnOnFileByModelCategories(List<String> modelCategories) {
        if (modelCategories == null || modelCategories.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, Object> params = getHashMap(2);
        params.put(KEY_FINISHED, ISystemConstant.IS_TRUE);
        params.put("modelCategories", modelCategories);
        List<String> processInstanceIds = oaOnFileDao.listUnOnFileProcessInstanceId(params);
        return listFinishedUnOnFile(new HashSet<>(processInstanceIds));
    }

    @Override
    public SuccessResultList<List<OaOnFileDTO>> listPage(ListPage page) {
        PageHelper.startPage(page.getPage(), page.getRows());
        List<OaOnFileDTO> oaOnFileDTOs = oaOnFileDao.list(page.getParams());
        PageInfo<OaOnFileDTO> pageInfo = new PageInfo<>(oaOnFileDTOs);
        setProcessInstanceParams(oaOnFileDTOs);
        return new SuccessResultList<>(oaOnFileDTOs, pageInfo.getPageNum(), pageInfo.getTotal());
    }

    @Override
    public SuccessResultList<List<OaOnFileDTO>> listPageByIds(List<String> onFileIds, ListPage page) {
        page.getParams().put("onFileIds", onFileIds);
        return listPage(page);
    }

    @Override
    public SuccessResultList<List<OaOnFileDTO>> listPageByFormCodeAndFormVersion(String formCode, Integer formVersion, ListPage page) {
        page.getParams().put(IFormDesignService.PARAM_FORM_CODE, formCode);
        page.getParams().put(IFormDesignService.PARAM_FORM_VERSION, formVersion);
        return listPage(page);
    }

    @Override
    public SuccessResultList<List<OaOnFileDTO>> listPageByProcessInstanceIds(List<String> processInstanceIds, ListPage page) {
        page.getParams().put("processInstanceIds", processInstanceIds);
        return listPage(page);
    }

    @Override
    public SuccessResultList<List<OaOnFileDTO>> listPageByReportUids(List<String> reportUids, ListPage page) {
        page.getParams().put("reportUids", reportUids);
        return listPage(page);
    }

    @Override
    public SuccessResultList<List<OaOnFileDTO>> listPageUnOnFile(ListPage page) {
        Map<String, Object> params = getHashMap(2);
        PageHelper.startPage(page.getPage(), page.getRows());
        List<String> processInstanceIds = oaOnFileDao.listUnOnFileProcessInstanceId(params);
        PageInfo<String> pageInfo = new PageInfo<>(processInstanceIds);
        List<OaOnFileDTO> oaOnFileDTOs = listUnOnFile(new HashSet<>(processInstanceIds));
        return new SuccessResultList<>(oaOnFileDTOs, pageInfo.getPageNum(), pageInfo.getTotal());
    }

    @Override
    public SuccessResultList<List<OaOnFileDTO>> listPageUnFinishedUnOnFile(ListPage page) {
        Map<String, Object> params = getHashMap(2);
        params.put(KEY_UN_FINISHED, ISystemConstant.IS_TRUE);
        PageHelper.startPage(page.getPage(), page.getRows());
        List<String> processInstanceIds = oaOnFileDao.listUnOnFileProcessInstanceId(params);
        PageInfo<String> pageInfo = new PageInfo<>(processInstanceIds);
        List<OaOnFileDTO> oaOnFileDTOs = listUnFinishedUnOnFile(new HashSet<>(processInstanceIds));
        return new SuccessResultList<>(oaOnFileDTOs, pageInfo.getPageNum(), pageInfo.getTotal());
    }

    @Override
    public SuccessResultList<List<OaOnFileDTO>> listPageFinishedUnOnFile(ListPage page) {
        Map<String, Object> params = getHashMap(2);
        params.put(KEY_FINISHED, ISystemConstant.IS_TRUE);
        PageHelper.startPage(page.getPage(), page.getRows());
        List<String> processInstanceIds = oaOnFileDao.listUnOnFileProcessInstanceId(params);
        PageInfo<String> pageInfo = new PageInfo<>(processInstanceIds);
        List<OaOnFileDTO> oaOnFileDTOs = listFinishedUnOnFile(new HashSet<>(processInstanceIds));
        return new SuccessResultList<>(oaOnFileDTOs, pageInfo.getPageNum(), pageInfo.getTotal());
    }

    @Override
    public SuccessResultList<List<OaOnFileDTO>> listPageFinishedUnOnFileByModelCategories(List<String> modelCategories, ListPage page) {
        if (modelCategories == null || modelCategories.isEmpty()) {
            return new SuccessResultList<>(new ArrayList<>(), 1, 0L);
        }
        Map<String, Object> params = getHashMap(2);
        params.put(KEY_FINISHED, ISystemConstant.IS_TRUE);
        params.put("modelCategories", modelCategories);
        PageHelper.startPage(page.getPage(), page.getRows());
        List<String> processInstanceIds = oaOnFileDao.listUnOnFileProcessInstanceId(params);
        PageInfo<String> pageInfo = new PageInfo<>(processInstanceIds);
        List<OaOnFileDTO> oaOnFileDTOs = listFinishedUnOnFile(new HashSet<>(processInstanceIds));
        return new SuccessResultList<>(oaOnFileDTOs, pageInfo.getPageNum(), pageInfo.getTotal());
    }

    /**
     * 设置流程参数
     *
     * @param oaOnFileDTOs
     */
    private void setProcessInstanceParams(List<OaOnFileDTO> oaOnFileDTOs) {
        if (oaOnFileDTOs.isEmpty()) {
            return;
        }
        List<String> processInstanceIds = ArrayListUtil.listBeanStringIdValue(oaOnFileDTOs, "processInstanceId", OaOnFileDTO.class);
        List<HistoricProcessInstance> historicProcessInstances = historyService.createHistoricProcessInstanceQuery()
                .processInstanceIds(new HashSet<>(processInstanceIds))
                .includeProcessVariables()
                .list();
        for (OaOnFileDTO oaOnFileDTO : oaOnFileDTOs) {
            for (HistoricProcessInstance historicProcessInstance : historicProcessInstances) {
                if (StringUtils.equals(oaOnFileDTO.getProcessInstanceId(), historicProcessInstance.getId())) {
                    Map<String, Object> processVariables = historicProcessInstance.getProcessVariables();
                    String mainTitle = (String) processVariables.get(IOaFormReportService.KEY_MAIN_TITLE);
                    oaOnFileDTO.setProcessDefinitionName(historicProcessInstance.getProcessDefinitionName());
                    oaOnFileDTO.setProcessStartTime(DateUtil.getDateTime(historicProcessInstance.getStartTime()));
                    if (historicProcessInstance.getEndTime() != null) {
                        oaOnFileDTO.setProcessEndTime(DateUtil.getDateTime(historicProcessInstance.getEndTime()));
                    }
                    oaOnFileDTO.setMainTitle(mainTitle);
                    break;
                }
            }
        }
    }

    /**
     * 未归档列表
     *
     * @param processInstanceIdSet
     * @return
     */
    private List<OaOnFileDTO> listUnOnFile(Set<String> processInstanceIdSet) {
        if (processInstanceIdSet.isEmpty()) {
            return new ArrayList<>();
        }
        return historyService.createHistoricProcessInstanceQuery()
                .processInstanceIds(processInstanceIdSet)
                .includeProcessVariables()
                .list()
                .stream().map(historicProcessInstance -> getOnFileDTO(historicProcessInstance)).collect(Collectors.toList());
    }

    /**
     * 未完成的未归档列表
     *
     * @param processInstanceIdSet
     * @return
     */
    private List<OaOnFileDTO> listUnFinishedUnOnFile(Set<String> processInstanceIdSet) {
        if (processInstanceIdSet.isEmpty()) {
            return new ArrayList<>();
        }
        return historyService.createHistoricProcessInstanceQuery()
                .processInstanceIds(new HashSet<>(processInstanceIdSet))
                .unfinished()
                .includeProcessVariables()
                .list()
                .stream().map(historicProcessInstance -> getOnFileDTO(historicProcessInstance)).collect(Collectors.toList());
    }

    /**
     * 已完成的未归档列表
     *
     * @param processInstanceIdSet
     * @return
     */
    private List<OaOnFileDTO> listFinishedUnOnFile(Set<String> processInstanceIdSet) {
        if (processInstanceIdSet.isEmpty()) {
            return new ArrayList<>();
        }
        return historyService.createHistoricProcessInstanceQuery()
                .processInstanceIds(new HashSet<>(processInstanceIdSet))
                .finished()
                .includeProcessVariables()
                .list()
                .stream().map(historicProcessInstance -> getOnFileDTO(historicProcessInstance)).collect(Collectors.toList());
    }

    private OaOnFileDTO getOnFileDTO(HistoricProcessInstance historicProcessInstance) {
        Map<String, Object> processVariables = historicProcessInstance.getProcessVariables();
        String formCode = (String) processVariables.get(IOaFormReportService.KEY_FORM_CODE);
        Integer formVersion = (Integer) processVariables.get(IOaFormReportService.KEY_FORM_VERSION);
        String reportUid = (String) processVariables.get(IOaFormReportService.KEY_REPORT_UID);
        String mainTitle = (String) processVariables.get(IOaFormReportService.KEY_MAIN_TITLE);
        OaOnFileDTO oaOnFileDTO = new OaOnFileDTO();
        oaOnFileDTO.setFormCode(formCode);
        oaOnFileDTO.setFormVersion(formVersion);
        oaOnFileDTO.setProcessInstanceId(historicProcessInstance.getId());
        oaOnFileDTO.setProcessDefinitionName(historicProcessInstance.getProcessDefinitionName());
        oaOnFileDTO.setProcessStartTime(DateUtil.getDateTime(historicProcessInstance.getStartTime()));
        if (historicProcessInstance.getEndTime() != null) {
            oaOnFileDTO.setProcessEndTime(DateUtil.getDateTime(historicProcessInstance.getEndTime()));
        }
        oaOnFileDTO.setReportUid(reportUid);
        oaOnFileDTO.setMainTitle(mainTitle);
        return oaOnFileDTO;
    }

}
