from io import StringIO
from typing import Tuple, Optional

from clarabot_nano_common.common.handler.error import NanoHandlerError
from clarabot_nano_common.common.protocol.errors import (
    NANO_REQUEST_ERROR_HANDLER_BAD_REQUEST,
    NANO_REQUEST_ERROR_HANDLER_DENIED,
)
from clarabot_nano_common.common.protocol.request import NanoRequestContext

from clarabot_nano.common.request.gateway import AbstractSpecificInterNanoJobRequest
from clarabot_nano.gateway.config import GatewayConfig
from clarabot_nano.gateway.handler.filesystem import AbstractFileSystemGatewayHandler
from clarabot_nano.gateway.state.gateway import GatewayState


class AbstractInterNanoJobHandler(AbstractFileSystemGatewayHandler):
    def __init__(self, helper: GatewayState, extracted_config: GatewayConfig, context: dict, payload: dict):
        AbstractFileSystemGatewayHandler.__init__(self, helper, extracted_config, context, payload)
        if not self.context.get(NanoRequestContext.ROOM):
            raise NanoHandlerError(NANO_REQUEST_ERROR_HANDLER_BAD_REQUEST, "Room is missing", self)
        if not self.can_write_drive():
            raise NanoHandlerError(NANO_REQUEST_ERROR_HANDLER_DENIED, "No permission", self)

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

    async def _execute_part(self, part: int, s_hmac_start_part: Optional[int]) -> dict:  # pragma: no cover
        raise NanoHandlerError(NANO_REQUEST_ERROR_HANDLER_BAD_REQUEST, "Part request is invalid", self)

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

    def build_error_message(self, buf: StringIO) -> None:
        raise NotImplementedError()


class AbstractSpecificInterNanoJobHandler(AbstractInterNanoJobHandler):
    def __init__(self, helper: GatewayState, extracted_config: GatewayConfig, context: dict, payload: dict):
        AbstractInterNanoJobHandler.__init__(self, helper, extracted_config, context, payload)
        job_id = self.payload.get(AbstractSpecificInterNanoJobRequest.JOB_ID)
        if not isinstance(job_id, int):
            raise NanoHandlerError(NANO_REQUEST_ERROR_HANDLER_BAD_REQUEST, "Invalid job-id", self)
        self.job_id = job_id

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

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

    def build_error_message(self, buf: StringIO) -> None:
        raise NotImplementedError()
