package com.jeeplus.flowable.common.handler;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.google.common.collect.Lists;
import com.jeeplus.common.TokenProvider;
import com.jeeplus.extension.domain.TaskDefExtension;
import com.jeeplus.extension.service.TaskDefExtensionService;
import com.jeeplus.extension.service.dto.FlowAssigneeDTO;
import com.jeeplus.flowable.feign.IAssessApi;
import com.jeeplus.flowable.feign.IFinanceApi;
import com.jeeplus.flowable.feign.IZsApi;
import com.jeeplus.flowable.utils.FlowableUtils;
import com.jeeplus.flowable.utils.StringUtils;
import com.jeeplus.sys.feign.IUserApi;
import com.jeeplus.sys.service.dto.UserDTO;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.UserTask;
import org.flowable.common.engine.impl.el.ExpressionManager;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.service.TaskService;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

import java.util.*;

@Slf4j
public class ExtUserTaskActivityBehavior extends UserTaskActivityBehavior {

    private static final long serialVersionUID = 7711531472879418236L;

    public ExtUserTaskActivityBehavior(UserTask userTask) {
        super ( userTask );
    }


    /**
     * 分配办理人员
     */
    @Override
    protected void handleAssignments(TaskService taskService, String assignee, String owner, List <String> candidateUsers, List <String> candidateGroups, TaskEntity task, ExpressionManager expressionManager, DelegateExecution execution, ProcessEngineConfigurationImpl processEngineConfiguration) {
        String currentToken = TokenProvider.getCurrentToken();

        Process process = SpringUtil.getBean ( RepositoryService.class ).getBpmnModel ( task.getProcessDefinitionId ( ) ).getMainProcess ( );
        FlowElement flowElement = process.getFlowElement ( task.getTaskDefinitionKey ( ) );
        Boolean isMultiInstance = FlowableUtils.isFlowElementMultiInstance ( flowElement );
        if ( isMultiInstance ) {
            super.handleAssignments ( taskService, assignee, owner, candidateUsers, candidateGroups, task, expressionManager, execution, processEngineConfiguration );
            return;
        }
        List <TaskDefExtension> list = SpringUtil.getBean ( TaskDefExtensionService.class )
                .lambdaQuery ( )
                .eq ( TaskDefExtension::getProcessDefId, process.getId ( ) )
                .eq ( TaskDefExtension::getTaskDefId, task.getTaskDefinitionKey ( ) ).list ( );
        HashSet <String> candidateUserIds = new LinkedHashSet <> ( );
        if ( list.size ( ) > 0 ) {
            TaskDefExtension taskDefExtension = list.get ( 0 );
            List <FlowAssigneeDTO> assigneeList = SpringUtil.getBean ( TaskDefExtensionService.class ).getById ( taskDefExtension.getId ( ) ).getFlowAssigneeList ( );
            IUserApi userApi = SpringUtil.getBean ( IUserApi.class );
            for (FlowAssigneeDTO flowAssignee : assigneeList) {
                switch (flowAssignee.getType ( )) {
                    case "user":
                        candidateUserIds.addAll ( Arrays.asList ( flowAssignee.getValue ( ).split ( "," ) ) );
                        break;
                    case "post":
                        if ( StrUtil.isNotBlank ( flowAssignee.getValue ( ) ) ) {
                            String postId = flowAssignee.getValue ( );
                            List <UserDTO> userList = userApi.findListFlowAbleByPostId ( postId );
                            candidateUserIds.addAll ( CollectionUtils.extractToList ( userList, "id" ) );
                        }

                        break;
                    case "company":
                        if ( StrUtil.isNotBlank ( flowAssignee.getValue ( ) ) ) {
                            String companyId = flowAssignee.getValue ( );
                            List <UserDTO> userList = userApi.findListByCompanyId ( companyId );
                            candidateUserIds.addAll ( CollectionUtils.extractToList ( userList, "id" ) );
                        }

                        break;
                    case "depart":
                        if ( StrUtil.isNotBlank ( flowAssignee.getValue ( ) ) ) {
                            String officeId = flowAssignee.getValue ( );
                            List <UserDTO> userList = userApi.findListByOfficeId ( officeId );
                            candidateUserIds.addAll ( CollectionUtils.extractToList ( userList, "id" ) );
                        }

                        break;
                    case "role":
                        if ( StrUtil.isNotBlank ( flowAssignee.getValue ( ) ) ) {
                            String[] roleIds = flowAssignee.getValue ( ).split ( "," );
                            for (String roleId : roleIds) {
                                List <UserDTO> userList = userApi.findListByRoleId ( roleId );
                                candidateUserIds.addAll ( CollectionUtils.extractToList ( userList, "id" ) );
                            }
                        }
                        break;
                    case "applyUserId":
                        candidateUserIds.add ( "${applyUserId}" );
                        break;
                    case "previousExecutor":
                        HistoricTaskInstance lastHisTask = SpringUtil.getBean ( HistoryService.class ).createHistoricTaskInstanceQuery ( ).processInstanceId ( task.getProcessInstanceId ( ) ).finished ( )
                                .includeProcessVariables ( ).orderByHistoricTaskInstanceEndTime ( ).desc ( ).list ( ).get ( 0 );

                        candidateUserIds.add ( lastHisTask.getAssignee ( ) );
                        break;
                    case "currentUserId":
                        candidateUserIds.add ( userApi.getByToken ( TokenProvider.getCurrentToken ( ) ).getId ( ) );
                        break;
                    case "sql":
                        Map userMap = SpringUtil.getBean ( JdbcTemplate.class ).queryForMap ( flowAssignee.getValue ( ) );
                        candidateUserIds.add ( userMap.get ( "id" ).toString ( ) );
                        break;
                    case "custom":
                        //根据你的自定义标记，请自行实现
                        //如果字符串中包含 "currentUserSql:" 则进行如下代码替换和处理
                        if(flowAssignee.getValue ().contains("currentUserSql:")){
                            //对应sql为：select su.* from sys_user_role a left join sys_role sr on sr.id = a.role_id left join sys_user su on su.id = a.user_id left join sys_office so on so.id = su.office_id where sr.en_name= 'bmzr' and so.id = (select office_id from sys_user where id = @currentUser.id)

                            UserDTO currentUserDTO = SpringUtil.getBean ( IUserApi.class ).getByToken (currentToken);

                            if(task.getFormKey().equals("/reimbursement/info/ReimbursementForm")){
                                if(StringUtils.isNotBlank(task.getProcessInstanceId())){
                                    //根据processInstanceId查询隶属报销中的创建人信息
                                    String createUserId = SpringUtil.getBean(IAssessApi.class).getReimbursementCreateUserIdByProcessInstanceId(task.getProcessInstanceId());
                                    if(StringUtils.isNotBlank(createUserId)){
                                        currentUserDTO = SpringUtil.getBean ( IUserApi.class ).getById (createUserId);
                                    }
                                }
                            }else if(task.getFormKey().equals("/cw/reimbursementApproval/info/ReimbursementForm")){

                                if(StringUtils.isNotBlank(task.getProcessInstanceId())){
                                    //根据processInstanceId查询隶属报销中的创建人信息
                                    String createUserId = SpringUtil.getBean(IFinanceApi.class).getReimbursementCreateUserIdByProcessInstanceId(task.getProcessInstanceId());
                                    if(StringUtils.isNotBlank(createUserId)){
                                        currentUserDTO = SpringUtil.getBean ( IUserApi.class ).getById (createUserId);
                                    }
                                }
                            }else if(task.getFormKey().equals("/zs/reimbursement/info/ReimbursementForm")){

                                if(StringUtils.isNotBlank(task.getProcessInstanceId())){
                                    //根据processInstanceId查询隶属报销中的创建人信息
                                    String createUserId = SpringUtil.getBean(IZsApi.class).getReimbursementCreateUserIdByProcessInstanceId(task.getProcessInstanceId());
                                    if(StringUtils.isNotBlank(createUserId)){
                                        currentUserDTO = SpringUtil.getBean ( IUserApi.class ).getById (createUserId);
                                    }
                                }
                            }
                            String sql = flowAssignee.getValue ();
                            if(sql.contains("@currentUser.id")){
                                //将标志进行去除
                                sql = sql.replaceAll("currentUserSql:","");
                                //将判断条件进行替换
                                sql = sql.replaceAll("@currentUser.id","'" + currentUserDTO.getId() + "'");
                            }
                            List<Map<String, Object>> maps = SpringUtil.getBean(JdbcTemplate.class).queryForList(sql);
                            for (Map<String, Object> map : maps) {
                                candidateUserIds.add(map.get ("id").toString ());
                            }
                        }
                        //如果字符串中包含 "cwCurrentUserSql:" 则进行如下代码替换和处理
                        if(flowAssignee.getValue ().contains("cwCurrentUserSql:")){
                            //对应sql为：select su.* from sys_user_role a left join sys_role sr on sr.id = a.role_id left join sys_user su on su.id = a.user_id left join sys_office so on so.id = su.office_id where sr.en_name= 'bmzr' and so.id = (select office_id from sys_user where id = @currentUser.id)
                            //用于查询当前登录人的部门主任人员信息
                            UserDTO currentUserDTO  = SpringUtil.getBean ( IUserApi.class ).getByToken (currentToken);
                            String sql = flowAssignee.getValue ();
                            if(sql.contains("@currentUser.id")){
                                //将标志进行去除
                                sql = sql.replaceAll("cwCurrentUserSql:","");
                                //将判断条件进行替换
                                sql = sql.replaceAll("@currentUser.id","'" + currentUserDTO.getId() + "'");
                            }
                            if(sql.contains("@currentUser.officeDTO.name")){
                                //将标志进行去除
                                sql = sql.replaceAll("cwCurrentUserSql:","");
                                //将判断条件进行替换
                                sql = sql.replaceAll("@currentUser.officeDTO.name","'" + currentUserDTO.getOfficeDTO().getName() + "'");
                            }
                            List<Map<String, Object>> maps = SpringUtil.getBean(JdbcTemplate.class).queryForList(sql);
                            for (Map<String, Object> map : maps) {
                                candidateUserIds.add(map.get ("id").toString ());
                            }
                        }
                        if(flowAssignee.getValue ().contains("zsbxCurrentUserSql:")){
                            //对应sql为：select su.* from sys_user_role a left join sys_role sr on sr.id = a.role_id left join sys_user su on su.id = a.user_id left join sys_office so on so.id = su.office_id where sr.en_name= 'bmzr' and so.id = (select office_id from sys_user where id = @currentUser.id)
                            //用于查询当前登录人的部门主任人员信息
                            UserDTO currentUserDTO = SpringUtil.getBean ( IUserApi.class ).getByToken (currentToken);
                            String sql = flowAssignee.getValue ();
                            if(sql.contains("@currentUser.id")){
                                //将标志进行去除
                                sql = sql.replaceAll("zsbxCurrentUserSql:","");
                                //将判断条件进行替换
                                sql = sql.replaceAll("@currentUser.id","'" + currentUserDTO.getId() + "'");
                            }
                            if(sql.contains("@currentUser.officeDTO.name")){
                                //将标志进行去除
                                sql = sql.replaceAll("zsbxCurrentUserSql:","");
                                //将判断条件进行替换
                                sql = sql.replaceAll("@currentUser.officeDTO.name","'" + currentUserDTO.getOfficeDTO().getName() + "'");
                            }
                            List<Map<String, Object>> maps = SpringUtil.getBean(JdbcTemplate.class).queryForList(sql);
                            for (Map<String, Object> map : maps) {
                                candidateUserIds.add(map.get ("id").toString ());
                            }
                        }
                        //如果字符串中包含 "gsldbxCurrentUserSql:" 则进行如下代码替换和处理
                        if(flowAssignee.getValue ().contains("gsldbxCurrentUserSql:")){
                            String sql = flowAssignee.getValue ();
                            // 流程发起人
                            ProcessInstance processInstance = SpringUtil.getBean(RuntimeService.class)
                                    .createProcessInstanceQuery()
                                    .processInstanceId(execution.getProcessInstanceId())
                                    .singleResult();
                            if(null != processInstance && StringUtils.isNotBlank(processInstance.getStartUserId())){
                                String startUserId = processInstance.getStartUserId();
                                //通过查询流程发起人确认发起人所在部门以及部门分管领导信息
                                if(sql.contains("@currentUser.id")){
                                    //将标志进行去除
                                    sql = sql.replaceAll("gsldbxCurrentUserSql:","");
                                    //将判断条件进行替换
                                    sql = sql.replaceAll("@currentUser.id","'" + startUserId + "'");
                                }
                            } else {
                                //如果找不到发起人信息 则审核人默认为 角色 总经办人员信息
                                sql = "SELECT su.* FROM sys_user_role a LEFT JOIN sys_role sr ON sr.id = a.role_id LEFT JOIN sys_user su ON su.id = a.user_id LEFT JOIN sys_office so ON so.id = su.office_id WHERE sr.en_name = 'zjb'";
                            }
                            //设定部门分管领导为审核人
                            List<Map<String, Object>> maps = SpringUtil.getBean(JdbcTemplate.class).queryForList(sql);
                            if(null == maps || maps.size()==0){
                                sql = "SELECT su.* FROM sys_user_role a LEFT JOIN sys_role sr ON sr.id = a.role_id LEFT JOIN sys_user su ON su.id = a.user_id LEFT JOIN sys_office so ON so.id = su.office_id WHERE sr.en_name = 'zjb'";
                                maps = SpringUtil.getBean(JdbcTemplate.class).queryForList(sql);
                            }
                            for (Map<String, Object> map : maps) {
                                candidateUserIds.add(map.get ("id").toString ());
                            }
                        }

                        break;
                }
            }
        }
        List <String> candidateIds = new ArrayList <> ( candidateUserIds );
        //此处可以根据业务逻辑自定义
        if ( candidateIds.size ( ) == 0 ) {
            super.handleAssignments ( taskService, null, owner, Lists.newArrayList ( ), Lists.newArrayList ( ), task, expressionManager, execution, processEngineConfiguration );
        } else if ( candidateIds.size ( ) == 1 ) {
            super.handleAssignments ( taskService, candidateIds.get ( 0 ), owner, Lists.newArrayList ( ), Lists.newArrayList ( ), task, expressionManager, execution, processEngineConfiguration );
        } else if ( candidateIds.size ( ) > 1 ) {
            super.handleAssignments ( taskService, null, owner, candidateIds, null, task, expressionManager, execution, processEngineConfiguration );
        }


    }

}

