from typing import Tuple, Optional

from clarabot_crypto.group_config.block import GroupConfigBlockMemberFlags

from clarabot_nano.common.config.constants import NanoServeAPI
from clarabot_nano.common.handler.base import NanoHandlerError
from clarabot_nano.common.protocol.errors import (
    NANO_REQUEST_ERROR_HANDLER_BAD_REQUEST,
    NANO_REQUEST_ERROR_HANDLER_FAILURE,
)
from clarabot_nano.common.protocol.request import NanoRequestContext
from clarabot_nano.server.base.config import ServerConfig
from clarabot_nano.server.base.handler.base import AbstractNanoServerHandler, ServerHandleHelper
from clarabot_nano.utility.path.chroot import ChrootPath
from clarabot_nano.utility.path.validate import ValidationError


class AbstractFileSystemHandler(AbstractNanoServerHandler):
    def __init__(self, helper: ServerHandleHelper, extracted_config: ServerConfig, context: dict, payload: dict):
        AbstractNanoServerHandler.__init__(self, helper, extracted_config, context, payload)
        if not isinstance(room := self.context.get(NanoRequestContext.ROOM), dict) or not (
            apis := room.get(NanoRequestContext.ROOM_APIS)
        ):
            raise NanoHandlerError(
                NANO_REQUEST_ERROR_HANDLER_BAD_REQUEST, "Request without room or apis cannot be executed", self.context
            )
        if not (drive := apis.get(NanoServeAPI.DRIVE_V2)):
            raise NanoHandlerError(
                NANO_REQUEST_ERROR_HANDLER_BAD_REQUEST, "Room of request has no drive api", self.context
            )
        # NOTE: Permissions flags allow access at least if we got here from the gateway.
        if not isinstance(root_path := drive.get("path"), str):
            raise NanoHandlerError(NANO_REQUEST_ERROR_HANDLER_FAILURE, "Drive path is missing", self.context)
        try:
            self.chroot = ChrootPath(root_path, restrict_sensitive=extracted_config.restrict_sensitive_path_access)
        except (OSError, ValidationError):
            raise NanoHandlerError(NANO_REQUEST_ERROR_HANDLER_FAILURE, "Drive path is invalid", self.context)

    def can_write_drive(self) -> bool:
        """
        NOTE: Anonymous access is always 0 (no permission flags are granted), but mutation handlers will reject
        anonymous requests anyway because of the mutation-id requirement.
        """
        return self.is_request_by_owner() or bool(
            self.context[NanoRequestContext.ROOM][NanoRequestContext.ROOM_CONFIG_MEMBER]
            & GroupConfigBlockMemberFlags.DRIVE_WRITE
        )

    def can_upload_drive(self) -> bool:
        """
        NOTE: Anonymous access is always 0 (no permission flags are granted), but mutation handlers will reject
        anonymous requests anyway because of the mutation-id requirement.
        """
        return self.is_request_by_owner() or bool(
            self.context[NanoRequestContext.ROOM][NanoRequestContext.ROOM_CONFIG_MEMBER]
            & GroupConfigBlockMemberFlags.DRIVE_UPLOAD
        )

    async def _create_request_key(self) -> Tuple[bool, Optional[list], int]:
        raise NotImplementedError()

    def _log_message(self) -> str:
        raise NotImplementedError()
