package com.xjrsoft.module.workflow.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.xjrsoft.common.constant.GlobalConstant;
import com.xjrsoft.common.enums.MenuType;
import com.xjrsoft.common.enums.WorkflowIsRecycleType;
import com.xjrsoft.common.enums.YesOrNoEnum;
import com.xjrsoft.common.exception.MyException;
import com.xjrsoft.module.organization.entity.User;
import com.xjrsoft.module.system.entity.Menu;
import com.xjrsoft.module.system.mapper.MenuMapper;
import com.xjrsoft.module.system.vo.MenuVo;
import com.xjrsoft.module.workflow.constant.WorkflowConstant;
import com.xjrsoft.module.workflow.dto.AddSpecialMenuDto;
import com.xjrsoft.module.workflow.dto.UpdateSpecialMenuDto;
import com.xjrsoft.module.workflow.entity.WorkflowSpecialMenu;
import com.xjrsoft.module.workflow.mapper.WorkflowSpecialMenuMapper;
import com.xjrsoft.module.workflow.model.SpecialMenuQueryConfig;
import com.xjrsoft.module.workflow.service.IWorkflowSpecialMenuService;
import com.xjrsoft.module.workflow.vo.SpecialMenuInfoVo;
import lombok.AllArgsConstructor;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.task.TaskQuery;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 专项菜单表 服务实现类
 * </p>
 *
 * @author tzx
 * @since 2023-03-20
 */
@Service
@AllArgsConstructor
public class WorkflowSpecialMenuServiceImpl extends MPJBaseServiceImpl<WorkflowSpecialMenuMapper, WorkflowSpecialMenu> implements IWorkflowSpecialMenuService {

    private final MenuMapper menuMapper;

    private final TaskService taskService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean add(AddSpecialMenuDto dto) {

        WorkflowSpecialMenu workflowSpecialMenu = BeanUtil.toBean(dto, WorkflowSpecialMenu.class);
        save(workflowSpecialMenu);

        Menu menu = BeanUtil.toBean(dto.getMenuInfo(), Menu.class);
        menu.setTitle(dto.getMenuInfo().getName());
        menu.setMenuType(MenuType.FUNCTION.getCode());
        menu.setDisplay(YesOrNoEnum.YES.getCode());
        menu.setAllowDelete(YesOrNoEnum.YES.getCode());
        menu.setAllowModify(YesOrNoEnum.YES.getCode());
        menu.setOutLink(YesOrNoEnum.NO.getCode());
        menu.setKeepAlive(YesOrNoEnum.NO.getCode());
        menu.setSortCode(dto.getMenuInfo().getSortCode());
        //固定路径  与前端必须匹配
        menu.setPath("/special-menu/" + workflowSpecialMenu.getId());
        menuMapper.insert(menu);

        WorkflowSpecialMenu updateSpecialMenu = new WorkflowSpecialMenu();
        updateSpecialMenu.setId(workflowSpecialMenu.getId());
        updateSpecialMenu.setMenuId(menu.getId());
        updateById(updateSpecialMenu);

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(UpdateSpecialMenuDto dto) {

        WorkflowSpecialMenu workflowSpecialMenu = BeanUtil.toBean(dto, WorkflowSpecialMenu.class);
        updateById(workflowSpecialMenu);

        Menu menu = BeanUtil.toBean(dto.getMenuInfo(), Menu.class);
        menuMapper.updateById(menu);

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(List<Long> ids) {

        List<WorkflowSpecialMenu> list = list(Wrappers.lambdaQuery(WorkflowSpecialMenu.class).in(WorkflowSpecialMenu::getId, ids).select(WorkflowSpecialMenu::getMenuId));

        List<Long> allMenuIds = list.stream().map(WorkflowSpecialMenu::getMenuId).collect(Collectors.toList());
        removeBatchByIds(ids);

        menuMapper.deleteBatchIds(allMenuIds);

        return true;
    }

    @Override
    public SpecialMenuInfoVo info(Long id) {

        WorkflowSpecialMenu specialMenu = getById(id);
        SpecialMenuInfoVo specialMenuInfoVo = BeanUtil.toBean(specialMenu, SpecialMenuInfoVo.class);

        Menu menu = menuMapper.selectById(specialMenu.getMenuId());
        specialMenuInfoVo.setMenuInfo(BeanUtil.toBean(menu, MenuVo.class));

        return specialMenuInfoVo;
    }

    @Override
    public List<Map<String, Object>> pending(Map<String, Object> param) {

        Long specialMenuId = MapUtil.get(param, WorkflowConstant.SPECIAL_MENU_ID_PARAM_NAME, Long.class);
        WorkflowSpecialMenu specialMenu = getById(specialMenuId);

        //最先判断当前操作人 是否有权限使用 此专项菜单。
        if (StrUtil.isBlank(specialMenu.getSchemaAuthUserId())) {
            throw new MyException("当前登陆人无操作权限！");
        }

        if (StrUtil.isBlank(specialMenu.getSchemaId())) {
            throw new MyException("当前专项菜单没有绑定模板！");
        }


        String[] userIds = specialMenu.getSchemaAuthUserId().split(StringPool.COMMA);
        if (Arrays.stream(userIds).noneMatch(u -> u.equals(StpUtil.getLoginIdAsString()))) {
            throw new MyException("当前登陆人无操作权限！");
        }

        //判断是多模板 还是单模板
        String schemaIdsStr = specialMenu.getSchemaId();
        String[] schemaIds = schemaIdsStr.split(StringPool.COMMA);
        List<SpecialMenuQueryConfig> specialMenuQueryConfigs = JSONUtil.toBean(specialMenu.getQueryConfig(), new TypeReference<List<SpecialMenuQueryConfig>>() {
        }, true);

        User user = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
        TaskQuery taskQuery = taskService.createTaskQuery()
                .active()
                .taskVariableValueEquals(WorkflowConstant.TASK_IS_APPOINT_APPROVE, YesOrNoEnum.NO.getCode())
                .processVariableValueEquals(WorkflowConstant.PROCESS_ISRECYCLE_FLAG_KEY, WorkflowIsRecycleType.NO.getCode())
                .taskVariableValueLike(WorkflowConstant.TASK_ASSIGNEE_VAR_KEY, StringPool.PERCENT + user.getId() + StringPool.PERCENT);
        //获取所有查询条件
        for (SpecialMenuQueryConfig specialMenuQueryConfig : specialMenuQueryConfigs) {
            if (specialMenuQueryConfig.getFieldName().equals(WorkflowConstant.SPECIAL_MENU_START_TIME_PARAM_NAME)) {
                Date starTime = MapUtil.get(param, WorkflowConstant.SPECIAL_MENU_START_TIME_PARAM_NAME, Date.class);
                taskQuery.taskCreatedAfter(starTime);
            }

            if (specialMenuQueryConfig.getFieldName().equals(WorkflowConstant.SPECIAL_MENU_END_TIME_PARAM_NAME)) {
                Date endTime = MapUtil.get(param, WorkflowConstant.SPECIAL_MENU_END_TIME_PARAM_NAME, Date.class);
                taskQuery.taskCreatedBefore(endTime);
            }

            if (specialMenuQueryConfig.getFieldName().equals(WorkflowConstant.SPECIAL_MENU_SERIAL_NUMBER_PARAM_NAME)) {
                Integer serialNumber = MapUtil.get(param, WorkflowConstant.SPECIAL_MENU_SERIAL_NUMBER_PARAM_NAME, Integer.class);
                taskQuery.processVariableValueEquals(WorkflowConstant.PROCESS_SERIAL_NUMBER_KEY, serialNumber);
            }

            if (specialMenuQueryConfig.getFieldName().equals(WorkflowConstant.SPECIAL_MENU_SCHEMA_NAME_PARAM_NAME)) {
                String schemaName = MapUtil.get(param, WorkflowConstant.SPECIAL_MENU_SCHEMA_NAME_PARAM_NAME, String.class);
                taskQuery.processVariableValueLike(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY, StringPool.PERCENT + schemaName + StringPool.PERCENT);
            }

            if (specialMenuQueryConfig.getFieldName().equals(WorkflowConstant.SPECIAL_MENU_ORIGINATOR_PARAM_NAME)) {
                String originator = MapUtil.get(param, WorkflowConstant.SPECIAL_MENU_ORIGINATOR_PARAM_NAME, String.class);
                taskQuery.or()
                        .processVariableValueEquals(WorkflowConstant.PROCESS_START_USER_NAME_KEY, originator)
                        .processVariableValueEquals(WorkflowConstant.PROCESS_START_USER_ID_KEY,originator)
                        .endOr();
            }

            if (specialMenuQueryConfig.getFieldName().equals(WorkflowConstant.SPECIAL_MENU_TASK_NAME_PARAM_NAME)) {
                String taskName = MapUtil.get(param, WorkflowConstant.SPECIAL_MENU_TASK_NAME_PARAM_NAME, String.class);
                taskQuery.taskNameLike(StringPool.PERCENT + taskName + StringPool.PERCENT);
            }




        }

        return null;
    }
}
