import asyncio
from io import StringIO
from typing import Tuple, Optional

from clarabot_nano_common.common.error import log_escape_str
from clarabot_nano_common.common.handler.base import NanoHandlerError
from clarabot_nano_common.common.protocol.errors import NANO_REQUEST_ERROR_HANDLER_BAD_REQUEST

from clarabot_nano.common.request.server_document import DocumentWsCloseRequest
from clarabot_nano.server.document.config import DocumentServerConfig
from clarabot_nano.server.document.handler.base import (
    AbstractDocumentSessionNanoServerHandler,
    DocumentServerHandleHelper,
)


class DocumentWsCloseHandler(AbstractDocumentSessionNanoServerHandler):
    REJECTS_ANONYMOUS_IDENTITY = False  # Further authorization is by room membership and group flags.
    EXECUTION_STATE_CAN_CONFLICT = False  # cacheable and request_key are constant, no conflict is possible
    ENSURE_WRITE_PERMISSION_CONSISTENCY = False  # Allow close command regardless.
    HANDLER_KEY = DocumentWsCloseRequest.TYPE_KEY

    def __init__(
        self, helper: DocumentServerHandleHelper, extracted_config: DocumentServerConfig, context: dict, payload: dict
    ):
        AbstractDocumentSessionNanoServerHandler.__init__(self, helper, extracted_config, context, payload)

    async def _create_request_key(self, secure: bool = False) -> Tuple[bool, Optional[list], int]:
        return self._secure_request_key(False, None, 1) if secure else False, None, 1

    async def _execute_initial(self) -> dict:
        d = await AbstractDocumentSessionNanoServerHandler._execute_initial(self)
        await asyncio.gather(self.document_session.stop(), return_exceptions=True)
        return d

    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:
        return f"Close document session {log_escape_str(self.session)}"

    def build_error_message(self, buf: StringIO) -> None:
        buf.write("Close document session ")
        buf.write(log_escape_str(self.payload.get(DocumentWsCloseRequest.SESSION)))
