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.interfaces.user.IUserBaseService;
import ink.wgink.module.activiti.dao.oa.IOaCcDao;
import ink.wgink.module.activiti.pojo.dtos.oa.OaCcDTO;
import ink.wgink.module.activiti.pojo.dtos.oa.OaStartedInstanceDTO;
import ink.wgink.module.activiti.pojo.pos.oa.OaCcPO;
import ink.wgink.module.activiti.pojo.vos.oa.OaCcVO;
import ink.wgink.module.activiti.service.oa.IOaCcService;
import ink.wgink.module.activiti.service.oa.IOaFormReportService;
import ink.wgink.module.form.service.design.IFormDesignService;
import ink.wgink.pojo.ListPage;
import ink.wgink.pojo.dtos.user.UserDTO;
import ink.wgink.pojo.result.SuccessResultList;
import ink.wgink.util.ArrayListUtil;
import ink.wgink.util.UUIDUtil;
import ink.wgink.util.map.HashMapUtil;
import org.activiti.engine.HistoryService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * @ClassName: FormCcServiceImpl
 * @Description: 表单抄送
 * @Author: wanggeng
 * @Date: 2022/5/9 11:28
 * @Version: 1.0
 */
@Service
public class OaCcServiceImpl extends DefaultBaseService implements IOaCcService {

    @Autowired
    private IOaCcDao oaCcDao;
    @Autowired
    private IUserBaseService userBaseService;
    @Autowired
    private HistoryService historyService;


    @Override
    public void save(OaCcVO oaCcVO) {
        String formCcId = UUIDUtil.getUUID();
        Map<String, Object> params = HashMapUtil.beanToMap(oaCcVO);
        params.put("ccId", formCcId);
        params.put("isRead", 0);
        setSaveInfo(params);
        oaCcDao.save(params);
    }

    @Override
    public void save(String token, OaCcVO oaCcVO) {
        String formCcId = UUIDUtil.getUUID();
        Map<String, Object> params = HashMapUtil.beanToMap(oaCcVO);
        params.put("ccId", formCcId);
        params.put("isRead", 0);
        setAppSaveInfo(token, params);
        oaCcDao.save(params);
    }

    @Override
    public void saveByUserId(String userId, OaCcVO oaCcVO) {
        String formCcId = UUIDUtil.getUUID();
        Map<String, Object> params = HashMapUtil.beanToMap(oaCcVO);
        params.put("ccId", formCcId);
        params.put("isRead", 0);
        setSaveInfoByUserId(params, userId);
        oaCcDao.save(params);
    }

    @Override
    public void saveByUserId(String saveUserId, String formCode, Integer formVersion, String processInstanceId, String reportUid, List<String> userIds) {
        if (userIds.isEmpty()) {
            return;
        }
        List<OaCcPO> oaCcPOS = listPOByReportUid(reportUid);
        for (String userId : userIds) {
            if (StringUtils.isBlank(userId)) {
                continue;
            }
            boolean isExist = false;
            for (OaCcPO oaCcPO : oaCcPOS) {
                if (StringUtils.equals(userId, oaCcPO.getUserId())) {
                    isExist = true;
                    break;
                }
            }
            if (isExist) {
                continue;
            }
            OaCcVO oaCcVO = new OaCcVO();
            oaCcVO.setFormCode(formCode);
            oaCcVO.setFormVersion(formVersion);
            oaCcVO.setProcessInstanceId(processInstanceId);
            oaCcVO.setReportUid(reportUid);
            oaCcVO.setUserId(userId);
            saveByUserId(saveUserId, oaCcVO);
        }
    }

    @Override
    public void updateRead(String ccId, int isRead) {
        Map<String, Object> params = getHashMap(4);
        params.put("ccId", ccId);
        params.put("isRead", isRead);
        setUpdateInfo(params);
        oaCcDao.updateRead(params);
    }

    @Override
    public void updateRead(String token, String ccId, int isRead) {
        Map<String, Object> params = getHashMap(4);
        params.put("ccId", ccId);
        params.put("isRead", isRead);
        setAppUpdateInfo(token, params);
        oaCcDao.updateRead(params);
    }

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

    @Override
    public List<OaCcPO> listPOByReportUid(String reportUid) {
        Map<String, Object> params = getHashMap(2);
        params.put("reportUid", reportUid);
        return listPO(params);
    }

    @Override
    public List<OaCcDTO> list(Map<String, Object> params) {
        params = params == null ? getHashMap(0) : params;
        List<OaCcDTO> oaCcDTOS = oaCcDao.list(params);
        setMainTitle(oaCcDTOS);
        setUserName(oaCcDTOS);
        return oaCcDTOS;
    }

    @Override
    public List<OaCcDTO> listByReportUid(String reportUid) {
        Map<String, Object> params = getHashMap(2);
        params.put("reportUid", reportUid);
        return list(params);
    }

    @Override
    public SuccessResultList<List<OaCcDTO>> listPage(ListPage page) {
        PageHelper.startPage(page.getPage(), page.getRows());
        List<OaCcDTO> oaCcDTOS = oaCcDao.list(page.getParams());
        setMainTitle(oaCcDTOS);
        setUserName(oaCcDTOS);
        PageInfo<OaCcDTO> pageInfo = new PageInfo<>(oaCcDTOS);
        return new SuccessResultList<>(oaCcDTOS, pageInfo.getPageNum(), pageInfo.getTotal());
    }

    @Override
    public SuccessResultList<List<OaCcDTO>> listPageByReportUid(String reportUid, ListPage page) {
        page.getParams().put("reportUid", reportUid);
        return listPage(page);
    }

    @Override
    public SuccessResultList<List<OaCcDTO>> listPageOfMineByIsRead(Integer isRead, ListPage page) {
        String userId = securityComponent.getCurrentUser().getUserId();
        return listPageByUserIdAndIsRead(userId, isRead, page);
    }

    @Override
    public SuccessResultList<List<OaCcDTO>> listPageOfMineByIsRead(String token, Integer isRead, ListPage page) {
        String userId = getAppTokenUser(token).getId();
        return listPageByUserIdAndIsRead(userId, isRead, page);
    }

    @Override
    public SuccessResultList<List<OaCcDTO>> listPageByUserIdAndIsRead(String userId, Integer isRead, ListPage page) {
        page.getParams().put("userId", userId);
        page.getParams().put("isRead", isRead);
        return listPage(page);
    }

    @Override
    public Integer countReadOfMine(int isRead) {
        String userId = securityComponent.getCurrentUser().getUserId();
        return countReadByUserId(userId, isRead);
    }

    @Override
    public Integer countReadOfMine(String token, int isRead) {
        String userId = getAppTokenUser(token).getId();
        return countReadByUserId(userId, isRead);
    }

    @Override
    public Integer countReadByUserId(String userId, int isRead) {
        Map<String, Object> params = getHashMap(4);
        params.put("userId", userId);
        params.put("isRead", isRead);
        return oaCcDao.count(params);
    }

    @Override
    public List<OaStartedInstanceDTO> listStartByUserId(String userId) {
        return listOaStartedInstance(historyService.createHistoricProcessInstanceQuery()
                .includeProcessVariables()
                .startedBy(userId)
                .orderByProcessInstanceStartTime()
                .desc()
                .list());
    }

    @Override
    public SuccessResultList<List<OaStartedInstanceDTO>> listPageStartByUserId(String userId, ListPage page) {
        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery()
                .startedBy(userId);
        long count = historicProcessInstanceQuery.count();
        List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery
                .includeProcessVariables()
                .orderByProcessInstanceStartTime()
                .desc()
                .listPage((page.getPage() - 1) * page.getRows(), page.getRows());
        return new SuccessResultList<>(listOaStartedInstance(historicProcessInstances), page.getPage(), count);
    }

    @Override
    public SuccessResultList<List<OaStartedInstanceDTO>> listPageStartOfMine(ListPage page) {
        return listPageStartByUserId(securityComponent.getCurrentUser().getUserId(), page);
    }

    private List<OaStartedInstanceDTO> listOaStartedInstance(List<HistoricProcessInstance> historicProcessInstances) {
        return historicProcessInstances.stream().map(historicProcessInstance -> {
            OaStartedInstanceDTO oaStartedInstanceDTO = new OaStartedInstanceDTO();
            oaStartedInstanceDTO.setDeploymentId(historicProcessInstance.getDeploymentId());
            oaStartedInstanceDTO.setProcessDefinitionId(historicProcessInstance.getProcessDefinitionId());
            oaStartedInstanceDTO.setProcessDefinitionKey(historicProcessInstance.getProcessDefinitionKey());
            oaStartedInstanceDTO.setProcessDefinitionName(historicProcessInstance.getProcessDefinitionName());
            oaStartedInstanceDTO.setProcessDefinitionVersion(historicProcessInstance.getProcessDefinitionVersion());
            oaStartedInstanceDTO.setProcessInstanceId(historicProcessInstance.getId());
            oaStartedInstanceDTO.setStartActivityId(historicProcessInstance.getStartActivityId());
            DateTime startDateTime = new DateTime(historicProcessInstance.getStartTime().getTime());
            startDateTime = startDateTime.minusHours(8);
            DateTime endDateTime = null;
            if (historicProcessInstance.getEndTime() != null) {
                endDateTime = new DateTime(historicProcessInstance.getEndTime().getTime());
                endDateTime = endDateTime.minusHours(8);
            }
            oaStartedInstanceDTO.setStartTime(startDateTime.toString(DateTimeFormat.forPattern(ISystemConstant.DATE_FORMATTER_YYYY_MM_DD_HH_MM_SS)));
            oaStartedInstanceDTO.setEndTime(endDateTime == null ? null : endDateTime.toString(DateTimeFormat.forPattern(ISystemConstant.DATE_FORMATTER_YYYY_MM_DD_HH_MM_SS)));
            oaStartedInstanceDTO.setStartUserId(historicProcessInstance.getStartUserId());
            Map<String, Object> processVariables = historicProcessInstance.getProcessVariables();
            oaStartedInstanceDTO.setFormCode((String) processVariables.get(IOaFormReportService.KEY_FORM_CODE));
            oaStartedInstanceDTO.setFormVersion((Integer) processVariables.get(IOaFormReportService.KEY_FORM_VERSION));
            oaStartedInstanceDTO.setReportUid((String) processVariables.get(IOaFormReportService.KEY_REPORT_UID));
            return oaStartedInstanceDTO;
        }).collect(Collectors.toList());
    }

    /**
     * 设置主标题
     *
     * @param oaCcDTOs
     */
    private void setMainTitle(List<OaCcDTO> oaCcDTOs) {
        if (oaCcDTOs.isEmpty()) {
            return;
        }
        List<String> processInstanceIds = ArrayListUtil.listBeanStringIdValue(oaCcDTOs, "processInstanceId", OaCcDTO.class);
        List<HistoricProcessInstance> processInstances = historyService.createHistoricProcessInstanceQuery()
                .processInstanceIds(new HashSet<>(processInstanceIds))
                .includeProcessVariables().list();
        oaCcDTOs.forEach(oaCcDTO -> {
            for (HistoricProcessInstance processInstance : processInstances) {
                if (StringUtils.equals(oaCcDTO.getProcessInstanceId(), processInstance.getId())) {
                    Map<String, Object> processVariables = processInstance.getProcessVariables();
                    String mainTitle = (String) processVariables.get(IFormDesignService.FIELD_MAIN_TITLE);
                    if (StringUtils.isBlank(mainTitle)) {
                        oaCcDTO.setMainTitle("您有一条待阅内容");
                    } else {
                        oaCcDTO.setMainTitle(mainTitle);
                    }
                    break;
                }
            }
        });
    }

    /**
     * 设置用户名
     *
     * @param oaCcDTOS
     */
    private void setUserName(List<OaCcDTO> oaCcDTOS) {
        if (oaCcDTOS.isEmpty()) {
            return;
        }
        Set<String> userIdSet = new HashSet<>();
        oaCcDTOS.forEach(oaCcDTO -> {
            userIdSet.add(oaCcDTO.getUserId());
        });
        List<UserDTO> userDTOs = userBaseService.listByUserIds(new ArrayList<>(userIdSet));
        if (userDTOs.isEmpty()) {
            return;
        }
        oaCcDTOS.forEach(oaCcDTO -> {
            for (UserDTO userDTO : userDTOs) {
                if (StringUtils.equals(oaCcDTO.getCreator(), userDTO.getUserId())) {
                    oaCcDTO.setCreatorName(userDTO.getUserName());
                }
                if (StringUtils.equals(oaCcDTO.getUserId(), userDTO.getUserId())) {
                    oaCcDTO.setUserName(userDTO.getUserName());
                }
            }
        });
    }

}
