package com.ruoyi.framework.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.core.domain.entity.Role;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.domain.vo.UserVO;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.framework.security.context.PermissionContextHolder;

/**
 * @author wjh
 * 2024/6/13
 * 更新时间 2024-10-18
 */
public class DataScopeUtil {

    /**
     * Mybatis直接使用的方法
     * @param deptAlias 部门别名
     * @param userAlias 用户别名
     * @param deptSetAlias 部门逗号分隔字段别名
     * @param userSetAlias 用户逗号分隔字段别名
     * @param needScope 是否需要数据隔离
     */
    public static String dataScope(String deptAlias, String userAlias, String deptSetAlias, String userSetAlias, boolean needScope) {
        return create(needScope)
            .deptAlias(deptAlias)
            .userAlias(userAlias)
            .deptSetAlias(deptSetAlias)
            .userSetAlias(userSetAlias)
            .build();
    }

    // 创建数据权限
    public static DataScopeBuilder create(boolean needScope) {
        DataScopeBuilder builder = DataScopeBuilder.create().needScope(needScope);
        if (needScope) {
            LoginUser loginUser = SecurityUtils.getLoginUser();
            if (StringUtils.isNotNull(loginUser)){
                UserVO user = loginUser.getUser();
                String permission = PermissionContextHolder.getContext();
                builder.user(user);
                builder.permission(permission);
            }
        }
        return builder;
    }

    // 获取数据权限SQL
    public static StringBuilder getSqlString(DataScopeBuilder builder) {
        UserVO user = builder.getUser();
        String deptAlias = builder.getDeptAlias();
        String userAlias = builder.getUserAlias();
        String appAlias = builder.getAppAlias();
        String deptSetAlias = builder.getDeptSetAlias();
        String userSetAlias = builder.getUserSetAlias();
        String permission = builder.getPermission();
        List<StoreStaffScope> storeStaffScopes = builder.getStoreStaffScopes();

        List<String> deptAliasList = StringUtils.hasText(deptAlias) ? Arrays.asList(deptAlias.split(",")) : new ArrayList<>();
        List<String> userAliasList = StringUtils.hasText(userAlias) ? Arrays.asList(userAlias.split(",")) : new ArrayList<>();
        List<String> deptSetAliasList = StringUtils.hasText(deptSetAlias) ? Arrays.asList(deptSetAlias.split(",")) : new ArrayList<>();
        List<String> userSetAliasList = StringUtils.hasText(userSetAlias) ? Arrays.asList(userSetAlias.split(",")) : new ArrayList<>();
        StringBuilder sqlString = new StringBuilder();
        List<String> conditions = new ArrayList<String>();
        List<String> scopeCustomIds = new ArrayList<String>();
        user.getRoles().forEach(role -> {
            if (DataScopeConstants.DATA_SCOPE_CUSTOM.equals(role.getDataScope())
                    && StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL)
                    && StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission))) {
                scopeCustomIds.add(Convert.toStr(role.getRoleId()));
            }
        });

        // 多个角色，逐一判断权限
        for (Role role : user.getRoles()) {
            String dataScope = role.getDataScope();
            if (conditions.contains(dataScope) || StringUtils.equals(role.getStatus(), UserConstants.ROLE_DISABLE)) {
                continue;
            }
            if (!StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission))) {
                continue;
            }
            // 全部数据范围
            if (DataScopeConstants.DATA_SCOPE_ALL.equals(dataScope)) {
                sqlString = new StringBuilder();
                conditions.add(dataScope);
                break;
            }
            // 自定义数据范围
            else if (DataScopeConstants.DATA_SCOPE_CUSTOM.equals(dataScope)) {
                if (scopeCustomIds.size() > 1) {
                    // 处理普通部门ID字段
                    sqlString.append(getForeachSql(" OR {} IN ( SELECT dept_id FROM sys_role_dept WHERE role_id in ({}) ) ", deptAliasList, String.join(",", scopeCustomIds)));
                    // 处理逗号分隔的部门ID字段
                    if (CollectionUtils.isNotEmpty(deptSetAliasList)) {
                        sqlString.append(" OR EXISTS ( SELECT 1 FROM sys_role_dept rd WHERE rd.role_id in (")
                                .append(String.join(",", scopeCustomIds))
                                .append(") AND (")
                                .append(getForeachSql("find_in_set(rd.dept_id, {}) OR ", deptSetAliasList))
                                .append(" 1=0)) ");
                    }
                } else {
                    // 处理普通部门ID字段
                    sqlString.append(getForeachSql(" OR {} IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAliasList, role.getRoleId()));
                    // 处理逗号分隔的部门ID字段
                    if (CollectionUtils.isNotEmpty(deptSetAliasList)) {
                        sqlString.append(" OR EXISTS ( SELECT 1 FROM sys_role_dept rd WHERE rd.role_id = ")
                                .append(role.getRoleId())
                                .append(" AND (")
                                .append(getForeachSql("find_in_set(rd.dept_id, {}) OR ", deptSetAliasList))
                                .append(" 1=0)) ");
                    }
                }
            }
            // 仅本部门
            else if (DataScopeConstants.DATA_SCOPE_DEPT.equals(dataScope)) {
                handleDeptDataScope(sqlString, deptAliasList, deptSetAliasList, user);
            }
            // 本部门及下级部门
            else if (DataScopeConstants.DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) {
                sqlString.append(getForeachSql(" OR {} IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
                        deptAliasList, user.getDeptId(), user.getDeptId()));
                if (CollectionUtils.isNotEmpty(deptSetAliasList)) {
                    sqlString.append(" OR EXISTS ( SELECT 1 FROM sys_dept d WHERE (d.dept_id = ")
                            .append(user.getDeptId())
                            .append(" OR find_in_set(")
                            .append(user.getDeptId())
                            .append(", d.ancestors)) AND (")
                            .append(getForeachSql("find_in_set(d.dept_id, {}) OR ", deptSetAliasList))
                            .append(" 1=0)) ");
                }
            }
            // 仅本人
            else if (DataScopeConstants.DATA_SCOPE_SELF.equals(dataScope)) {
                handleUserDataScope(sqlString, userAliasList, userSetAliasList, user);
            }
            // 本人及本部门
            else if (DataScopeConstants.DATA_SCOPE_DEPT_AND_SELF.equals(dataScope) ) {
                handleDeptDataScope(sqlString, deptAliasList, deptSetAliasList, user);
                handleUserDataScope(sqlString, userAliasList, userSetAliasList, user);
            }
            // 负责部门数据权限
            else if (DataScopeConstants.DATA_SCOPE_LEADER_DEPT.equals(dataScope)) {
                sqlString.append(getForeachSql(" OR {} in ( SELECT dept_id FROM sys_dept WHERE find_in_set({}, leader_ids) )",
                        deptAliasList, user.getUserId()));
                if (CollectionUtils.isNotEmpty(deptSetAliasList)) {
                    sqlString.append(" OR EXISTS ( SELECT 1 FROM sys_dept d WHERE find_in_set(")
                            .append(user.getUserId())
                            .append(", d.leader_ids) AND (")
                            .append(getForeachSql("find_in_set(d.dept_id, {}) OR ", deptSetAliasList))
                            .append(" 1=0)) ");
                }
            }
            // 负责的APP数据权限
            else if (DataScopeConstants.DATA_SCOPE_APP_OWNER.equals(dataScope)) {
                sqlString.append(String.format(" OR %s in ( SELECT bst_app.id FROM bst_app WHERE find_in_set(%s, bst_app.owner_ids) )",
                        appAlias, user.getUserId()));
            }
            // 本人及运维店铺数据权限
            else if (DataScopeConstants.DATA_SCOPE_STORE_AND_SELF.equals(dataScope)) {
                // 处理本人数据
                handleUserDataScope(sqlString, userAliasList, userSetAliasList, user);
                // 处理运维的店铺数据
                if (CollectionUtils.isNotEmptyElement(storeStaffScopes)) {
                    for (StoreStaffScope storeStaffScope : storeStaffScopes) {
                        String sql = StringUtils.format(
                                " OR {} IN ( SELECT distinct bss.store_id FROM bst_store_staff bss WHERE bss.user_id = {} and find_in_set('{}', bss.permissions))",
                                storeStaffScope.getStoreAlias(), user.getUserId(), storeStaffScope.getPermission()
                        );
                        sqlString.append(sql);
                    }
                }
            }
            conditions.add(dataScope);
        }

        // 角色都不包含传递过来的权限字符，这个时候sqlString也会为空，所以要限制一下,不查询任何数据
        if (StringUtils.isEmpty(conditions)) {
            sqlString.append(" OR 1=0 ");
        }

        return sqlString;
    }

    // 处理本人
    private static void handleUserDataScope(StringBuilder sqlString, List<String> userAliasList, List<String> userSetAliasList, UserVO user) {
        if (CollectionUtils.isNotEmpty(userAliasList)) {
            sqlString.append(getForeachSql(" OR {} = {} ", userAliasList, user.getUserId()));
        }
        // 处理存储多个用户ID的字段
        if (CollectionUtils.isNotEmpty(userSetAliasList)) {
            sqlString.append(getForeachSql(" OR find_in_set({}, {}) ", user.getUserId(), userSetAliasList));
        }
        // 如果两种字段都没有，则不查询任何数据
        if (CollectionUtils.isEmpty(userAliasList) && CollectionUtils.isEmpty(userSetAliasList)) {
            sqlString.append(" OR 1=0 ");
        }
    }

    // 处理部门
    private static void handleDeptDataScope(StringBuilder sqlString, List<String> deptAliasList, List<String> deptSetAliasList, UserVO user) {
        sqlString.append(getForeachSql(" OR {} = {} ", deptAliasList, user.getDeptId()));
        if (CollectionUtils.isNotEmpty(deptSetAliasList)) {
            sqlString.append(getForeachSql(" OR find_in_set({}, {}) ", user.getDeptId(), deptSetAliasList));
        }
    }

    /**
     * 获取列表循环SQL
     */
    private static String getForeachSql(String template, List<String> list, Object ...others) {
        StringBuilder sb = new StringBuilder();
        for (String s : list) {
            // 创建一个新的数组，包含 s 和 others 的所有元素
            Object[] params = new Object[others.length + 1];
            params[0] = s; // 将 s 放在第一个位置
            System.arraycopy(others, 0, params, 1, others.length); // 将 others 中的元素依次放入新数组中
            sb.append(StringUtils.format(template, params));
        }
        return sb.toString();
    }

    private static String getForeachSql(String template, Object obj, List<String> list) {
        StringBuilder sb = new StringBuilder();
        for (String s : list) {
            sb.append(StringUtils.format(template, obj, s));
        }
        return sb.toString();
    }


    public static void joinSqlString(BaseEntity baseEntity, StringBuilder sqlString) {
        String scope = (String) baseEntity.getParams().get(DataScopeConstants.DATA_SCOPE);
        baseEntity.getParams().put(DataScopeConstants.DATA_SCOPE, getJoinSqlString(sqlString, scope));
    }

    public static String getJoinSqlString(StringBuilder sqlString, String scope) {
        return " AND (" + scope + sqlString.substring(4) + ")";
    }

}
