from fastapi import Depends, Request, params
from sqlalchemy import ColumnElement, func, or_, select

from common.context import RequestContext
from config.database import Base
from module_admin.entity.do.dept_do import SysDept
from module_admin.entity.do.role_do import SysRoleDept
from utils.dependency_util import DependencyUtil


class GetDataScope:
    """
    获取当前用户数据权限对应的查询sql语句
    """

    DATA_SCOPE_ALL = '1'
    DATA_SCOPE_CUSTOM = '2'
    DATA_SCOPE_DEPT = '3'
    DATA_SCOPE_DEPT_AND_CHILD = '4'
    DATA_SCOPE_SELF = '5'

    def __init__(
        self,
        query_alias: Base,
        user_alias: str | None = 'user_id',
        dept_alias: str | None = 'dept_id',
    ) -> None:
        """
        获取当前用户数据权限对应的查询sql语句

        :param query_alias: 所要查询表对应的sqlalchemy模型类，不可为空
        :param user_alias: 用户id字段别名，默认为'user_id'
        :param dept_alias: 部门id字段别名，默认为'dept_id'
        """
        self.query_alias = query_alias
        self.user_alias = user_alias
        self.dept_alias = dept_alias

    def __call__(self, request: Request) -> ColumnElement:
        DependencyUtil.check_exclude_routes(request, err_msg='当前路由不在认证规则内，不可使用GetDataScope依赖项')
        current_user = RequestContext.get_current_user()
        user_id = current_user.user.user_id
        dept_id = current_user.user.dept_id
        custom_data_scope_role_id_list = [
            item.role_id for item in current_user.user.role if item.data_scope == self.DATA_SCOPE_CUSTOM
        ]
        param_sql_list = []
        for role in current_user.user.role:
            if current_user.user.admin or role.data_scope == self.DATA_SCOPE_ALL:
                param_sql_list = [True]
                break
            if role.data_scope == self.DATA_SCOPE_CUSTOM:
                if len(custom_data_scope_role_id_list) > 1:
                    param_sql_list.append(
                        getattr(self.query_alias, self.dept_alias).in_(
                            select(SysRoleDept.dept_id).where(SysRoleDept.role_id.in_(custom_data_scope_role_id_list))
                        )
                        if hasattr(self.query_alias, self.dept_alias)
                        else False
                    )
                else:
                    param_sql_list.append(
                        getattr(self.query_alias, self.dept_alias).in_(
                            select(SysRoleDept.dept_id).where(SysRoleDept.role_id == role.role_id)
                        )
                        if hasattr(self.query_alias, self.dept_alias)
                        else False
                    )
            elif role.data_scope == self.DATA_SCOPE_DEPT:
                param_sql_list.append(
                    getattr(self.query_alias, self.dept_alias) == dept_id
                    if hasattr(self.query_alias, self.dept_alias)
                    else False
                )
            elif role.data_scope == self.DATA_SCOPE_DEPT_AND_CHILD:
                param_sql_list.append(
                    getattr(self.query_alias, self.dept_alias).in_(
                        select(SysDept.dept_id).where(
                            or_(SysDept.dept_id == dept_id, func.find_in_set(dept_id, SysDept.ancestors))
                        )
                    )
                    if hasattr(self.query_alias, self.dept_alias)
                    else False
                )
            elif role.data_scope == self.DATA_SCOPE_SELF:
                param_sql_list.append(
                    getattr(self.query_alias, self.user_alias) == user_id
                    if hasattr(self.query_alias, self.user_alias)
                    else False
                )
            else:
                param_sql_list.append(False)
        param_sql_list = list(dict.fromkeys(param_sql_list))
        param_sql = or_(*param_sql_list)

        return param_sql


def DataScopeDependency(  # noqa: N802
    query_alias: Base,
    user_alias: str | None = 'user_id',
    dept_alias: str | None = 'dept_id',
) -> params.Depends:
    """
    当前用户数据权限依赖

    :param query_alias: 所要查询表对应的sqlalchemy模型类，不可为空
    :param user_alias: 用户id字段别名，默认为'user_id'
    :param dept_alias: 部门id字段别名，默认为'dept_id'
    :return: 当前用户数据权限依赖
    """
    return Depends(GetDataScope(query_alias, user_alias, dept_alias))
