package jnpf.personnels.utils;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jnpf.base.ActionResult;
import jnpf.base.UserInfo;
import jnpf.base.entity.SuperBaseEntity;
import jnpf.cultivate.utils.AsyncExamQuestionUtils;
import jnpf.database.util.TenantDataSourceUtil;
import jnpf.model.personnels.dto.authoritys.PermissionsCacheDTO;
import jnpf.model.personnels.po.FtbPersonnelsPermissions;
import jnpf.model.personnels.vo.authoritys.FtbPermissionUserVO;
import jnpf.permission.OrganizeApi;
import jnpf.permission.UserApi;
import jnpf.permission.dto.user.DecideUserUnderlingDTO;
import jnpf.permission.model.user.SubordinateUserInfoVO;
import jnpf.personnels.mapper.FtbPersonnelsPermissionsMapper;
import jnpf.util.UserProvider;
import jnpf.utils.FeignHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Nullable;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.stream.Collectors;


/**
 * 人事权限工具类
 *
 * @author fantaibao
 * @date 2024/02/06
 */
@Slf4j
@Component
public class PersonnelPerUtils {

    @Resource
    private FtbPersonnelsPermissionsMapper ftbPersonnelsPermissionsMapper;

    @Autowired
    private UserApi userApi;

    @Autowired
    private OrganizeApi organizeApi;

    @Autowired
    private AsyncExamQuestionUtils asyncExamQuestionUtils;

    /**
     * 获取培训批阅人id
     *
     * @return {@link String}
     */
    @Nullable
    public String obtainTrainingApproverPermissions(String userId) {
        return doObtainTrainUserPermissions(List.of("70"), userId);
    }

    /**
     * 获取培训审核案例人所具有的用户id
     *
     * @return {@link String} 用户id，逗号隔开
     */
    @Nullable
    public String obtainReviewCasePermissions(String userId) {
        return doObtainTrainUserPermissionsSpecify(List.of("135"), userId, 1);
    }

    /**
     * 获取培训实操鉴定人id
     *
     * @return {@link String}
     */
    @Nullable
    public String obtainTrainedAppraiser(String userId) {
        return doObtainTrainUserPermissions(List.of("71"), userId);
    }

    /**
     * 获取人事用户数据权限，返回为空，则表示为超级管理员（可以查询所有数据）
     *
     * @return {@link List} 用户id
     */
    @Nullable
    public List<String> obtainPersonnelDataPermissions() {
        UserInfo userInfo = UserProvider.getUser();
        if (userInfo.getIsAdministrator()) {
            return null;
        }
        List<String> userIds = obtainPersonnelDataPermissions0(userInfo, 0);
        if (CollectionUtils.isEmpty(userIds)) {
            throw new RuntimeException("该用户暂未设置人事数据权限，请对该用户设置权限");
        }
        return userIds;
    }

    /**
     * 获取人事用户数据权限，返回为空，则表示为超级管理员（可以查询所有数据）
     *
     * @return {@link List} 组织id
     */
    @Nullable
    public List<String> obtainPersonnelOrganizationIdDataPermissions() {
        UserInfo userInfo = UserProvider.getUser();
        if (userInfo.getIsAdministrator()) {
            return null;
        }
        List<String> orgIds = obtainPersonnelOrganizationIdDataPermissions0(userInfo, 0);
        if (CollectionUtils.isEmpty(orgIds)) {
            throw new RuntimeException("该用户暂未设置人事数据权限，请对该用户设置权限");
        }
        return orgIds;
    }

    /**
     * 根据组织id获取该组织“办理入职”权限的人员
     *
     * @return {@link List} 用户id
     */
    @Nullable
    public List<String> obtainPersonnelUserIdDataPermissionsByOrgId(String orgId, String userId, String... tenantIds) {
        // 办理入职
        List<FtbPermissionUserVO> userVOS = ftbPersonnelsPermissionsMapper.queryFtbPermissionUserVoByAuthorityId(List.of("133", "134"));
        String tenantId = tenantIds.length > 0 ? tenantIds[0] : null;
        Predicate<FtbPermissionUserVO> predicate = a -> {
            if (a.getScopePermission() == 2) {
                // 校验是否为下属关系
                DecideUserUnderlingDTO dto = new DecideUserUnderlingDTO();
                dto.setUserId(userId);
                dto.setManagerId(a.getUserId());
                dto.setTenantId(tenantId);
                ActionResult<Boolean> booleanActionResult = userApi.decideUnderling(dto);
                if (booleanActionResult.getCode() == 200) {
                    return booleanActionResult.getData();
                }
            }
            // 所在组织和下级组织员工
            if (a.getScopePermission() == 0) {
                return doCheckDataPermissionsByOrgId(
                        tenantId != null
                                ? organizeApi.getOrganizeIdsAdnChildByUserIdAndTenantId(a.getUserId(), tenantId)
                                : organizeApi.getOrganizeIdsAdnChildByUserId(a.getUserId())
                        , orgId);
            }
            // 所在组织员工
            if (a.getScopePermission() == 1) {
                return doCheckDataPermissionsByOrgId(
                        tenantId != null
                                ? organizeApi.getOrganizeIdsByUserIdAndTenantId(a.getUserId(), tenantId)
                                : organizeApi.getOrganizeIdsByUserId(a.getUserId())
                        , orgId);
            }
            // 指定组织
            if (a.getScopePermission() == 3) {
                return doCheckDataPermissionsByOrgId(List.of(a.getSpecifyOrgIds().split(StringPool.COMMA)), orgId);
            }
            return false;
        };
        return userVOS.stream()
                .filter(predicate)
                .map(FtbPermissionUserVO::getUserId)
                .collect(Collectors.toList());
    }

    private List<String> obtainPersonnelOrganizationIdDataPermissions0(UserInfo userInfo, Integer permissionType) {
        FtbPersonnelsPermissions ftbPersonnelsPermissions = doPermissionQuery(userInfo, permissionType);
        if (Objects.isNull(ftbPersonnelsPermissions)) {
            return null;
        }
        if (ftbPersonnelsPermissions.getScopePermission() == 2) {
            throw new RuntimeException("该用户数据权限为仅下属，暂无权限办理或查看");
        }
        // 所在组织和下级组织员工
        if (ftbPersonnelsPermissions.getScopePermission() == 0) {
            return organizeApi.getOrganizeIdsAdnChildByUserId(userInfo.getUserId());
        }
        // 所在组织员工
        if (ftbPersonnelsPermissions.getScopePermission() == 1) {
            return organizeApi.getOrganizeIdsByUserId(userInfo.getUserId());
        }
        // 指定组织
        if (ftbPersonnelsPermissions.getScopePermission() == 3) {
            return List.of(ftbPersonnelsPermissions.getSpecifyOrgIds().split(StringPool.COMMA));
        }
        return null;
    }


    private List<String> obtainPersonnelDataPermissions0(UserInfo userInfo, Integer permissionType) {
        FtbPersonnelsPermissions ftbPersonnelsPermissions = doPermissionQuery(userInfo, permissionType);
        if (Objects.isNull(ftbPersonnelsPermissions)) {
            return null;
        }
        return doGetUserIds(userInfo, ftbPersonnelsPermissions);
    }

    @Nullable
    private List<String> doGetUserIds(UserInfo userInfo, FtbPersonnelsPermissions ftbPersonnelsPermissions) {
        // 权限适用范围,0所在组织和下级组织员工,1所在组织员工,2仅下属，3指定组织
        if (ftbPersonnelsPermissions.getScopePermission() == 2) {
          //  List<UserSubordinateVO> userSubordinateVOS = userApi.userSubordinateVOListByLeaderId(userInfo.getUserId());
            List<SubordinateUserInfoVO> subordinateUserInfoVOS = userApi.userInfoByLeaderId(userInfo.getUserId());
            if (CollectionUtils.isNotEmpty(subordinateUserInfoVOS)) {
                return subordinateUserInfoVOS.stream()
                        .map(SubordinateUserInfoVO::getUserId)
                        .collect(Collectors.toList());
            }else {
                throw new RuntimeException("暂未查询到下属用户信息!");
            }
        }
        if (ftbPersonnelsPermissions.getScopePermission() == 3) {
            List<String> orgIds = List.of(ftbPersonnelsPermissions.getSpecifyOrgIds().split(StringPool.COMMA));
            ActionResult<List<String>> userIdListByOrganizeIds = userApi.getUserIdListByOrganizeIds(orgIds);
            if (CollectionUtils.isEmpty(userIdListByOrganizeIds.getData())) {
                throw new RuntimeException("暂未查询到指定组织员工！");
            }
            return userIdListByOrganizeIds.getData().stream().distinct().collect(Collectors.toList());
        }
        // 所在组织
        List<String> orgIds = organizeApi.getOrganizeIdsByUserId(userInfo.getUserId());
        // 所在组织和下级组织员工
        if (ftbPersonnelsPermissions.getScopePermission() == 0) {
            ActionResult<List<String>> listActionResult = userApi.getUserIdListByOrganizeIdsAndChild(orgIds);
            if (CollectionUtils.isEmpty(listActionResult.getData())) {
                throw new RuntimeException("暂未查询到所在组织和下级组织员工！");
            }
            return listActionResult.getData().stream().distinct().collect(Collectors.toList());
        }
        // 所在组织员工
        if (ftbPersonnelsPermissions.getScopePermission() == 1) {
            ActionResult<List<String>> userIdListByOrganizeIds = userApi.getUserIdListByOrganizeIds(orgIds);
            if (CollectionUtils.isEmpty(userIdListByOrganizeIds.getData())) {
                throw new RuntimeException("暂未查询到所在组织员工！");
            }
            return userIdListByOrganizeIds.getData().stream().distinct().collect(Collectors.toList());
        }
        return null;
    }

    private FtbPersonnelsPermissions doPermissionQuery(UserInfo userInfo, Integer permissionType) {
        LambdaQueryWrapper<FtbPersonnelsPermissions> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(FtbPersonnelsPermissions::getEnableMark, 0);
        queryWrapper.eq(FtbPersonnelsPermissions::getPermissionType, permissionType);
        queryWrapper.eq(FtbPersonnelsPermissions::getUserId, userInfo.getUserId());
        return ftbPersonnelsPermissionsMapper.selectOne(queryWrapper);
    }

    @Nullable
    private String doObtainTrainUserPermissions(List<String> permissionIds, String userId) {
        List<String> reviewerPermissions = ftbPersonnelsPermissionsMapper.getReviewerPermissions(permissionIds);
        if (CollectionUtils.isEmpty(reviewerPermissions)) {
            return null;
        }
        LambdaQueryWrapper<FtbPersonnelsPermissions> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(FtbPersonnelsPermissions::getEnableMark, 0);
        queryWrapper.in(SuperBaseEntity.SuperIBaseEntity::getId, reviewerPermissions);
        List<FtbPersonnelsPermissions> ftbPersonnelsPermissions = ftbPersonnelsPermissionsMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(ftbPersonnelsPermissions)) {
            return null;
        }
        // 校验是否有关联关系
        List<String> userIds = new ArrayList<>();
        // 查询用户所属组织做筛选
        List<String> localOrganizeIds = organizeApi.getOrganizeIdsByUserId(userId);
        for (FtbPersonnelsPermissions ftbPersonnelsPermission : ftbPersonnelsPermissions) {
            if (ftbPersonnelsPermission.getScopePermission() == 2) {
                // 通过人员去排查
                List<SubordinateUserInfoVO> subordinateUserInfoVOS = userApi.userInfoByLeaderId(ftbPersonnelsPermission.getUserId());
                if (CollectionUtils.isEmpty(subordinateUserInfoVOS)) {
                    continue;
                }
                List<String> childrenUserIds = subordinateUserInfoVOS.stream()
                        .map(SubordinateUserInfoVO::getUserId)
                        .collect(Collectors.toList());
                if (childrenUserIds.contains(userId)) {
                    userIds.add(ftbPersonnelsPermission.getUserId());
                }
            }
            // 所在组织和下级组织员工,查询组织id进行比对
            List<String> organizeIdsAdnChildByUserId = null;
            if (ftbPersonnelsPermission.getScopePermission() == 0) {
                organizeIdsAdnChildByUserId = organizeApi.getOrganizeIdsAdnChildByUserId(ftbPersonnelsPermission.getUserId());
            }
            // 所在组织员工,查询组织id进行比对
            if (ftbPersonnelsPermission.getScopePermission() == 1) {
                organizeIdsAdnChildByUserId = organizeApi.getOrganizeIdsByUserId(ftbPersonnelsPermission.getUserId());
            }
            // 指定组织
            if (ftbPersonnelsPermission.getScopePermission() == 3) {
                organizeIdsAdnChildByUserId = Arrays.asList(ftbPersonnelsPermission.getSpecifyOrgIds().split(StringPool.COMMA));
            }
            if (haveIntersection(localOrganizeIds, organizeIdsAdnChildByUserId)) {
                userIds.add(ftbPersonnelsPermission.getUserId());
            }
        }
        if (CollectionUtils.isNotEmpty(userIds)) {
            return String.join(",", userIds);
        }
        return null;
    }

    public PermissionsCacheDTO doQueryUserPermissions(List<String> permissionIds) {
        PermissionsCacheDTO permissionsCacheDTO = new PermissionsCacheDTO();
        List<String> reviewerPermissions = ftbPersonnelsPermissionsMapper.getReviewerPermissions(permissionIds);
        if (CollectionUtils.isEmpty(reviewerPermissions)) {
            return permissionsCacheDTO;
        }
        LambdaQueryWrapper<FtbPersonnelsPermissions> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(FtbPersonnelsPermissions::getEnableMark, 0);
        queryWrapper.in(SuperBaseEntity.SuperIBaseEntity::getId, reviewerPermissions);
        List<FtbPersonnelsPermissions> ftbPersonnelsPermissions = ftbPersonnelsPermissionsMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(ftbPersonnelsPermissions)) {
            return permissionsCacheDTO;
        }
        // 校验是否有关联关系
        ConcurrentHashMap<FtbPersonnelsPermissions, List<String>> allUserListIdsMap = new ConcurrentHashMap<>();
        ConcurrentHashMap<FtbPersonnelsPermissions, List<String>> allOrgListMap = new ConcurrentHashMap<>();
        String tenantId = asyncExamQuestionUtils.getTenantId();
        Map<String, String> headers = asyncExamQuestionUtils.getHeadersForLogin();
        // 查询用户所属组织做筛选
        ftbPersonnelsPermissions.parallelStream().forEach(ftbPersonnelsPermission -> {
            try {
                FeignHolder.set(headers);
                TenantDataSourceUtil.switchTenant(tenantId);
                if (ftbPersonnelsPermission.getScopePermission() == 2) {
                    // 通过人员去排查
                    List<SubordinateUserInfoVO> subordinateUserInfoVOS = userApi.userInfoByLeaderId(ftbPersonnelsPermission.getUserId());
                    if (CollectionUtils.isEmpty(subordinateUserInfoVOS)) {
                        return;
                    }
                    List<String> childrenUserIds = subordinateUserInfoVOS.stream()
                            .map(SubordinateUserInfoVO::getUserId)
                            .collect(Collectors.toList());
                    if (CollectionUtils.isNotEmpty(childrenUserIds)) {
                        allUserListIdsMap.put(ftbPersonnelsPermission, childrenUserIds);
                    }
                }
                // 所在组织和下级组织员工,查询组织id进行比对
                List<String> organizeIdsAdnChildByUserId = null;
                if (ftbPersonnelsPermission.getScopePermission() == 0) {
                    organizeIdsAdnChildByUserId = organizeApi.getOrganizeIdsAdnChildByUserId(ftbPersonnelsPermission.getUserId());
                }
                // 所在组织员工,查询组织id进行比对
                if (ftbPersonnelsPermission.getScopePermission() == 1) {
                    organizeIdsAdnChildByUserId = organizeApi.getOrganizeIdsByUserId(ftbPersonnelsPermission.getUserId());
                }
                // 指定组织
                if (ftbPersonnelsPermission.getScopePermission() == 3) {
                    organizeIdsAdnChildByUserId = Arrays.asList(ftbPersonnelsPermission.getSpecifyOrgIds().split(StringPool.COMMA));
                }
                if (CollectionUtils.isNotEmpty(organizeIdsAdnChildByUserId)) {
                    allOrgListMap.put(ftbPersonnelsPermission, organizeIdsAdnChildByUserId);
                }
            } catch (Exception e) {
                log.error("多线程查询权限:tenantCode={}", tenantId);
            } finally {
                FeignHolder.clear();
            }
        });

        permissionsCacheDTO.setAllUserListIdsMap(allUserListIdsMap);
        permissionsCacheDTO.setAllOrgListMap(allOrgListMap);
        return permissionsCacheDTO;
    }

    @Nullable
    private String doObtainTrainUserPermissionsSpecify(List<String> permissionIds, String userId, Integer permissionType) {
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(userId);
        FtbPersonnelsPermissions ftbPersonnelsPermissions = doPermissionQuery(userInfo, permissionType);
        if (Objects.isNull(ftbPersonnelsPermissions)) {
            // 未对此人设置培训权限
            return null;
        }
        // 校验此用户是否设置了permissionIds的权限
        List<String> reviewerPermissions = ftbPersonnelsPermissionsMapper.getReviewerPermissions(permissionIds);
        if (CollectionUtils.isEmpty(reviewerPermissions)) {
            return null;
        }
        if (reviewerPermissions.contains(ftbPersonnelsPermissions.getId())) {
            List<String> userIds = doGetUserIds(userInfo, ftbPersonnelsPermissions);
            if (CollectionUtils.isEmpty(userIds)) {
                return null;
            }
            return String.join(StringPool.COMMA, userIds);
        }
        return null;
    }

    public boolean haveIntersection(List<String> localOrganizeIds, List<String> organizeIdsByUserId) {
        if (CollectionUtils.isEmpty(localOrganizeIds) || CollectionUtils.isEmpty(organizeIdsByUserId)) {
            return false;
        }
        // 小数据驱动大数据
        for (String localOrganizeId : localOrganizeIds) {
            if (organizeIdsByUserId.contains(localOrganizeId)) {
                return true;
            }
        }
        return false;
    }

    private boolean doCheckDataPermissionsByOrgId(List<String> orgIds, String organizationId) {
        if (CollUtil.isEmpty(orgIds)) {
            return false;
        }
        return orgIds.contains(organizationId);
    }

}
