package com.yh.saas.platform.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import com.winsea.svc.base.workflow.entity.Workflow;
import com.winsea.svc.base.workflow.entity.WorkflowStep;
import com.yh.saas.toolkit.workflow.exception.WorkflowErrorCodeEnums;
import com.yh.saas.toolkit.workflow.exception.WorkflowException;
import com.yh.saas.toolkit.workflow.service.IWorkflowService;
import com.yh.saas.toolkit.workflow.service.IWorkflowStepService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alipay.sofa.runtime.api.annotation.SofaReference;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.google.common.collect.Lists;
import com.winsea.svc.base.base.entity.CommonRole;
import com.winsea.svc.base.base.entity.CommonStaff;
import com.winsea.svc.base.base.entity.CommonStaffRole;
import com.winsea.svc.base.base.service.ICommonRoleService;
import com.winsea.svc.base.base.service.ICommonStaffRoleService;
import com.winsea.svc.base.base.service.ICommonStaffService;
import com.yh.saas.platform.entity.view.FlowTaskCandidateStaffView;
import com.yh.saas.platform.entity.view.FlowTaskCandidateStaffView.CandidateType;
import com.yh.saas.platform.service.IFlowTaskCandidateService;
import com.yh.saas.toolkit.workflow.activiti.util.ActivitiProcessUtils;
import com.yh.saas.toolkit.workflow.activiti.util.ActivitiTaskUtils;

/**
 * 流程候选人服务实现
 *
 * @author SunTianjun
 */
@Service
public class FlowTaskCandidateServiceImpl implements IFlowTaskCandidateService {

	@SofaReference
	private ICommonStaffService staffService;

	@SofaReference
	private ICommonRoleService roleService;

	@SofaReference
	private ICommonStaffRoleService staffRoleService;

	@Autowired
	private IWorkflowService workflowService;

	@Autowired
	private IWorkflowStepService workflowStepService;


	@Override
	public FlowTaskCandidateStaffView getCandidateStaffInfo(String flowId, String businessKey) {
		FlowTaskCandidateStaffView flowTaskCandidateStaffView = buildStaffView(flowId, businessKey);
		if (null == flowTaskCandidateStaffView) {
			flowTaskCandidateStaffView = buildRoleStaffView(flowId, businessKey);
		}

		if (null == flowTaskCandidateStaffView) {
			flowTaskCandidateStaffView = new FlowTaskCandidateStaffView();
			flowTaskCandidateStaffView.setCandidateType(CandidateType.NONE);
		}

		return flowTaskCandidateStaffView;
	}


	@Override
	public FlowTaskCandidateStaffView findPreReveiewerStaffInfo(String businessCode) {
		//查询当前步骤最新审核流
		Workflow workflow = this.workflowService.findLatestWorkflowByBusinessCode(businessCode);
		if (null == workflow) {
			throw new WorkflowException(WorkflowErrorCodeEnums.WORKFLOW_NULL);
		}

		//查询步骤
		List<WorkflowStep> workflowSteps = workflowStepService.getDetailByWorkflowId(workflow.getId());
		WorkflowStep preWorkflowStep = null;
		for (int i = 0; i < workflowSteps.size(); i++) {
			WorkflowStep workflowStep = workflowSteps.get(i);
			if (!"_PLACEHOLDER_".equals(workflowStep.getDesc())) {
				if (!WorkflowStep.StepType.NORMAL.equals(workflowStep.getStepType())) {
					throw new WorkflowException(WorkflowErrorCodeEnums.WORKFLOW_STEP_NOT_NORMAL);
				}
				preWorkflowStep = workflowStep;
				break;
			}
		}

		if (null == preWorkflowStep) {
			throw new WorkflowException(WorkflowErrorCodeEnums.WORKFLOW_STEP_NULL);
		}

		//带选择角色
		List<CommonStaffRole> staffRoles = null;
		List<FlowTaskCandidateStaffView.RoleStaffView> roleStaffViews = new ArrayList<>();

		FlowTaskCandidateStaffView flowTaskCandidateStaffView = new FlowTaskCandidateStaffView();

		//查出审核人
		String auditType = StringUtils.isEmpty(preWorkflowStep.getAuditRoles()) ? "staff" : "role";
		if ("staff".equals(auditType)) {
			List<String> staffIds = Lists.newArrayList(preWorkflowStep.getAuditUsers().split(","));
			flowTaskCandidateStaffView.setCandidateType(CandidateType.STAFF);
			flowTaskCandidateStaffView.setStaffs(staffService.findStaffs(staffIds));
			return flowTaskCandidateStaffView;
		} else {
			List<String> roleIds = Lists.newArrayList(preWorkflowStep.getAuditRoles().split(","));
			staffRoles = staffRoleService.findStaff(roleIds);
			Map<String, List<CommonStaffRole>> staffRoleMap = staffRoles.stream().collect(Collectors.groupingBy(CommonStaffRole::getRoleId));

			for (String roleId : staffRoleMap.keySet()) {
				List<String> staffIds = staffRoleMap.get(roleId).stream().map(CommonStaffRole::getStaffId).collect(Collectors.toList());
				FlowTaskCandidateStaffView.RoleStaffView roleStaffView = new FlowTaskCandidateStaffView.RoleStaffView();
				roleStaffView.setRole(roleService.selectById(roleId));
				roleStaffView.setStaffs(staffService.findStaffs(staffIds));
				roleStaffViews.add(roleStaffView);
			}

			flowTaskCandidateStaffView.setCandidateType(CandidateType.ROLE_STAFF);
			flowTaskCandidateStaffView.setRoleStaffs(roleStaffViews);
			return flowTaskCandidateStaffView;
		}
	}


	/**
	 * 构建候选人信息<br/>
	 * 候选人类型为职员
	 *
	 * @param flowId      流程ID
	 * @param businessKey 业务ID
	 * @return 候选人信息
	 */
	private FlowTaskCandidateStaffView buildStaffView(String flowId, String businessKey, String deptId) {
		FlowTaskCandidateStaffView flowTaskCandidateStaffView = null;
		List<String> staffIds = ActivitiTaskUtils.getCurrentSingleActiveTaskUsers(flowId, businessKey);
		if (!staffIds.isEmpty()) {
			flowTaskCandidateStaffView = new FlowTaskCandidateStaffView();
			flowTaskCandidateStaffView.setCandidateType(CandidateType.STAFF);
			List<CommonStaff> staffList = staffIds.stream().map(staffId -> staffService.selectById(staffId))
					.collect(Collectors.toList());
			if (StringUtils.isNotBlank(deptId)) {
				flowTaskCandidateStaffView.setStaffs(staffList.stream()
						.filter(staff -> StringUtils.equals(deptId, staff.getDeptId())).collect(Collectors.toList()));
			} else {
				flowTaskCandidateStaffView.setStaffs(staffList);
			}
			flowTaskCandidateStaffView.setCurrentActiveTaskId(setCurrentActiveTaskId(flowId, businessKey));

			// 2020年3月4日17:03:22 整理数据 跟职务人员一样,使前端不用改变原有的数据结构
			integratedData(flowTaskCandidateStaffView);
		}
		return flowTaskCandidateStaffView;
	}

	/**
	 * 构建候选人信息<br/>
	 * 候选人类型为职员
	 *
	 * @param flowId      流程ID
	 * @param businessKey 业务ID
	 * @return 候选人信息
	 */
	private FlowTaskCandidateStaffView buildStaffView(String flowId, String businessKey) {
		FlowTaskCandidateStaffView flowTaskCandidateStaffView = null;
		List<String> staffIds = ActivitiTaskUtils.getCurrentSingleActiveTaskUsers(flowId, businessKey);
		if (!staffIds.isEmpty()) {
			flowTaskCandidateStaffView = new FlowTaskCandidateStaffView();
			flowTaskCandidateStaffView.setCandidateType(CandidateType.STAFF);
			flowTaskCandidateStaffView.setStaffs(
					staffIds.stream().map(staffId -> staffService.selectById(staffId)).collect(Collectors.toList()));

			flowTaskCandidateStaffView.setCurrentActiveTaskId(setCurrentActiveTaskId(flowId, businessKey));

			//2020年3月4日17:03:22 整理数据 跟职务人员一样,使前端不用改变原有的数据结构
			integratedData(flowTaskCandidateStaffView);
		}
		return flowTaskCandidateStaffView;
	}


	/**
	 * 通过角色下所有职员
	 *
	 * @param roleId 角色ID
	 * @return 职员列表
	 */
	private List<CommonStaff> getStaffsByRoleId(String roleId) {
		List<CommonStaffRole> staffRoles = staffRoleService
				.selectList(new EntityWrapper<CommonStaffRole>().eq(CommonStaffRole.QueryFields.ROLE_ID, roleId));

		return staffRoles.stream().map(staffRole -> staffService.selectById(staffRole.getStaffId()))
				.collect(Collectors.toList());
	}

	/**
	 * 获取当前活动的任务ID
	 *
	 * @param flowId      流程ID
	 * @param businessKey 业务ID
	 * @return 当前活动的任务ID
	 */
	private String setCurrentActiveTaskId(String flowId, String businessKey) {
		return ActivitiTaskUtils.getActiveTask(
				ActivitiProcessUtils.findInstanceByWorkflowIdAndBusinessKey(flowId, businessKey).getProcessInstanceId())
				.getId();
	}

	/**
	 * 整合数据清理下
	 */
	private void integratedData(FlowTaskCandidateStaffView flowTaskCandidateStaffView) {
		Map<String, CommonStaff> staffMap = flowTaskCandidateStaffView.getStaffs().stream()
				.collect(Collectors.toMap(CommonStaff::getStaffId, staff -> staff));
		List<String> staffIds = Lists.newArrayList(staffMap.keySet());
		// 只获取主要职务
		List<CommonStaffRole> staffRoles = staffRoleService.findStaffRoles(staffIds).stream()
				.filter(staffRole -> "1".equals(staffRole.getRoleMajor())).collect(Collectors.toList());
		Set<String> roleIds = staffRoles.stream().map(CommonStaffRole::getRoleId).collect(Collectors.toSet());

		flowTaskCandidateStaffView.getStaffs().clear();
		List<FlowTaskCandidateStaffView.RoleStaffView> roleStaffViews = new ArrayList<>();
		roleIds.forEach(roleId -> {
			CommonRole role = this.roleService.selectById(roleId);
			List<String> newStaffIds = staffRoleService.findStaff(Lists.newArrayList(roleId)).stream()
					.map(CommonStaffRole::getStaffId).collect(Collectors.toList());
			newStaffIds.retainAll(staffIds);
			List<CommonStaff> staffs = new ArrayList<>();
			for (String staffId : newStaffIds) {
				staffs.add(staffMap.get(staffId));
			}

			FlowTaskCandidateStaffView.RoleStaffView roleStaffView = new FlowTaskCandidateStaffView.RoleStaffView();
			roleStaffView.setRole(role);
			roleStaffView.setStaffs(staffs);
			roleStaffViews.add(roleStaffView);
		});

		flowTaskCandidateStaffView.setRoleStaffs(roleStaffViews);
	}

	/**
	 * 构建候选人信息<br/>
	 * 候选人类型为角色职员
	 *
	 * @param flowId      流程ID
	 * @param businessKey 业务ID
	 * @return 候选人信息
	 */
	private FlowTaskCandidateStaffView buildRoleStaffView(String flowId, String businessKey) {
		FlowTaskCandidateStaffView flowTaskCandidateStaffView = null;
		List<String> roleIds = ActivitiTaskUtils.getCurrentSingleActiveTaskRoles(flowId, businessKey);
		if (!roleIds.isEmpty()) {
			flowTaskCandidateStaffView = new FlowTaskCandidateStaffView();
			flowTaskCandidateStaffView.setCurrentActiveTaskId(setCurrentActiveTaskId(flowId, businessKey));
			flowTaskCandidateStaffView.setCandidateType(CandidateType.ROLE_STAFF);
			flowTaskCandidateStaffView.setRoleStaffs(new ArrayList<>());

			for (String roleId : roleIds) {
				FlowTaskCandidateStaffView.RoleStaffView roleStaffView = new FlowTaskCandidateStaffView.RoleStaffView();
				roleStaffView.setRole(roleService.selectById(roleId));
				roleStaffView.setStaffs(getStaffsByRoleId(roleId));

				flowTaskCandidateStaffView.getRoleStaffs().add(roleStaffView);
			}
		}
		return flowTaskCandidateStaffView;
	}


}
