package org.lingniu.idp.service.core;

import org.lingniu.idp.constant.Constants;
import org.lingniu.idp.constant.UserConstants;
import org.lingniu.idp.model.entity.SysDept;
import org.lingniu.idp.model.entity.SysRole;
import org.lingniu.idp.model.entity.SysUser;
import org.lingniu.idp.model.vo.DataPermission;
import org.lingniu.idp.service.ISysDeptService;
import org.lingniu.idp.service.ISysMenuService;
import org.lingniu.idp.service.ISysRoleService;
import org.lingniu.idp.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 用户权限处理
 * 
 * @author portal
 */
@Component
public class SysPermissionService
{
    @Autowired
    private ISysRoleService roleService;

    @Autowired
    private ISysMenuService menuService;
    @Autowired
    private ISysDeptService deptService;

    /**
     * 获取角色数据权限
     * 
     * @param user 用户信息
     * @return 角色权限信息
     */
    public Set<String> getRolePermission(SysUser user)
    {
        Set<String> roles = new HashSet<String>();
        // 管理员拥有所有权限
        if (user.isAdmin())
        {
            roles.add(Constants.SUPER_ADMIN);
        }
        else
        {
            roles.addAll(roleService.selectRolePermissionByUserId(user.getUserId()));
        }
        return roles;
    }

    /**
     * 获取数据权限
     * @return
     * 1=所有数据权限,2=自定义数据权限,3=本部门及以下数据权限,4=本部门数据权限,5=仅本人数据权限
     **/
    public DataPermission getDataPermission(SysUser user) {
        // 1. 管理员看所有
        if (user.isAdmin()) {
            return DataPermission.builder().allowAll(true).build();
        }

        // 2. 获取用户角色并处理
        List<SysRole> sysRoles = roleService.selectRolesByUserId(user.getUserId());
        ProcessResult processResult = processRoles(sysRoles);

        // 3. 如果没有有效范围值，返回默认仅看自己
        return processResult.minScopeExcluding2()
                .map(scope -> buildDataPermissionByScope(scope, processResult, user))
                .orElse(DataPermission.builder().onlySelf(true).build());
    }

    public record ProcessResult(Optional<Integer> minScopeExcluding2, boolean hasScope2) {}

    private ProcessResult processRoles(List<SysRole> sysRoles) {
        boolean hasScope2 = sysRoles.stream()
                .anyMatch(role -> "2".equals(role.getDataScope()));

        Optional<Integer> minScopeExcluding2 = sysRoles.stream()
                .map(SysRole::getDataScope)
                .filter(scope -> !"2".equals(scope))
                .map(this::parseScopeToInt)
                .flatMap(Optional::stream)
                .min(Integer::compareTo);

        return new ProcessResult(minScopeExcluding2, hasScope2);
    }

    private DataPermission buildDataPermissionByScope(Integer scope, ProcessResult processResult, SysUser user) {
        return switch (scope) {
            case 1 -> DataPermission.builder().allowAll(true).build();
            case 3 -> buildDataPermissionForScope3(processResult, user);
            case 4 -> buildDataPermissionForScope4(processResult, user);
            case 5 -> buildDataPermissionForScope5(processResult, user);
            default -> DataPermission.builder().onlySelf(true).build();
        };
    }

    private DataPermission buildDataPermissionForScope3(ProcessResult processResult, SysUser user) {
        Set<String> deptSet = new HashSet<>();
        Set<String> areaSet = new HashSet<>();

        // 添加本部门及以下部门
        user.getDeptList().forEach(dept -> {
            List<SysDept> children = deptService.selectChildrenDeptById(dept.getDeptId());
            addDeptAndAreaInfo(children, deptSet, areaSet);
        });

        // 添加自定义部门（如果有）
        if (processResult.hasScope2()) {
            List<SysDept> customDepts = deptService.selectDeptListByUserRole(user.getUserId());
            addDeptAndAreaInfo(customDepts, deptSet, areaSet);
        }

        return DataPermission.builder().deptList(deptSet).areas(areaSet).build();
    }

    private DataPermission buildDataPermissionForScope4(ProcessResult processResult, SysUser user) {
        return buildDataPermissionWithCustomDeptsOnly(processResult, user, false);
    }

    private DataPermission buildDataPermissionForScope5(ProcessResult processResult, SysUser user) {
        return buildDataPermissionWithCustomDeptsOnly(processResult, user, true);
    }

    private DataPermission buildDataPermissionWithCustomDeptsOnly(ProcessResult processResult, SysUser user, boolean onlySelf) {
        Set<String> deptSet = new HashSet<>();
        Set<String> areaSet = new HashSet<>();

        if (processResult.hasScope2()) {
            List<SysDept> customDepts = deptService.selectDeptListByUserRole(user.getUserId());
            addDeptAndAreaInfo(customDepts, deptSet, areaSet);
        }

        return DataPermission.builder()
                .deptList(deptSet)
                .areas(areaSet)
                .onlySelf(onlySelf)
                .build();
    }

    private void addDeptAndAreaInfo(List<SysDept> deptList, Set<String> deptSet, Set<String> areaSet) {
        deptList.forEach(dept -> {
            deptSet.add(String.valueOf(dept.getDeptId()));
            if (dept.getAreaId() != null) {
                areaSet.add(String.valueOf(dept.getAreaId()));
            }
        });
    }

    private Optional<Integer> parseScopeToInt(String scope) {
        try {
            return Optional.of(Integer.parseInt(scope));
        } catch (NumberFormatException e) {
            return Optional.empty();
        }
    }
    /**
     * 获取菜单数据权限
     * 
     * @param user 用户信息
     * @return 菜单权限信息
     */
    public Set<String> getMenuPermission(SysUser user)
    {
        Set<String> perms = new HashSet<String>();
        // 管理员拥有所有权限
        if (user.isAdmin())
        {
            perms.add(Constants.ALL_PERMISSION);
        }
        else
        {
            List<SysRole> roles = user.getRoles();
            if (!CollectionUtils.isEmpty(roles))
            {
                // 多角色设置permissions属性，以便数据权限匹配权限
                for (SysRole role : roles)
                {
                    if (StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL) && !role.isAdmin())
                    {
                        Set<String> rolePerms = menuService.selectMenuPermsByRoleId(role.getRoleId());
                        role.setPermissions(rolePerms);
                        perms.addAll(rolePerms);
                    }
                }
            }
            else
            {
                perms.addAll(menuService.selectMenuPermsByUserId(user.getUserId()));
            }
        }
        return perms;
    }
}
