from typing import Optional, Union

from core.database.abc.db_model_dao_abc import DbModelDaoABC
from core.database.external_data_temp_table_builder import ExternalDataTempTableBuilder
from core.logger import DBLogger
from data.schemas.administration.user import User
from data.schemas.permission.permission_dao import permissionDao
from service.permission.permissions_enum import Permissions

logger = DBLogger(__name__)


class UserDao(DbModelDaoABC[User]):

    def __init__(self):
        DbModelDaoABC.__init__(self, __name__, User, "administration.users")

        self.attribute(User.keycloak_id, str, aliases=["keycloakId"])

        async def get_users():
            return [(x.id, x.username, x.email) for x in await self.get_all()]

        self.use_external_fields(
            ExternalDataTempTableBuilder()
            .with_table_name(self._table_name)
            .with_field("id", "int", True)
            .with_field("username", "text")
            .with_field("email", "text")
            .with_value_getter(get_users)
        )

    async def get_by_keycloak_id(self, keycloak_id: str) -> User:
        return await self.get_single_by({User.keycloak_id: keycloak_id})

    async def find_by_keycloak_id(self, keycloak_id: str) -> Optional[User]:
        return await self.find_single_by({User.keycloak_id: keycloak_id})

    async def has_permission(
        self, user_id: int, permission: Union[Permissions, str]
    ) -> bool:
        p = await permissionDao.get_by_name(
            permission if isinstance(permission, str) else permission.value
        )
        result = await self._db.select_map(
            f"""
            SELECT COUNT(*)
            FROM permission.role_users ru
            JOIN permission.role_permissions rp ON ru.roleId = rp.roleId
            WHERE ru.userId = {user_id}
            AND rp.permissionId = {p.id}
            AND ru.deleted = FALSE
            AND rp.deleted = FALSE;
        """
        )
        if result is None or len(result) == 0:
            return False

        return result[0]["count"] > 0

    async def get_permissions(self, user_id: int) -> list[Permissions]:
        result = await self._db.select_map(
            f"""
            SELECT p.*
            FROM permission.permissions p
            JOIN permission.role_permissions rp ON p.id = rp.permissionId
            JOIN permission.role_users ru ON rp.roleId = ru.roleId
            WHERE ru.userId = {user_id}
            AND rp.deleted = FALSE
            AND ru.deleted = FALSE;
            """
        )
        return [Permissions(p["name"]) for p in result]


userDao = UserDao()
