from io import StringIO
from typing import Optional, Tuple

from clarabot_nano_common.common.handler.error import NanoHandlerError
from clarabot_nano_common.common.protocol.errors import NANO_REQUEST_ERROR_HANDLER_BAD_REQUEST
from clarabot_nano_common.common.protocol.request import NanoRequestContext

from clarabot_nano.server.document.config import DocumentServerConfig
from clarabot_nano.server.document.handler.base import AbstractDocumentNanoServerHandler, DocumentServerHandleHelper


class DebugInternalAuthInfoHandler(AbstractDocumentNanoServerHandler):
    EXECUTION_STATE_CAN_CONFLICT = False  # cacheable and request_key are constant, no conflict is possible
    ALLOW_INTERNAL_REQUEST_EXECUTION = True

    HANDLER_KEY = "debug-intern-auth"

    def __init__(
        self, helper: DocumentServerHandleHelper, extracted_config: DocumentServerConfig, context: dict, payload: dict
    ):
        AbstractDocumentNanoServerHandler.__init__(self, helper, extracted_config, context, payload)
        self.account_id = self.payload.get("i_account_id")
        if not isinstance(self.account_id, int):
            raise NanoHandlerError(NANO_REQUEST_ERROR_HANDLER_BAD_REQUEST, "bad i_account_id", self)
        self.room_id = self.payload.get("i_room_id")
        if not isinstance(self.room_id, int):
            raise NanoHandlerError(NANO_REQUEST_ERROR_HANDLER_BAD_REQUEST, "bad i_room_id", self)
        self.request = self.payload.get("i_request")
        if self.request is not None and not isinstance(self.request, dict):
            raise NanoHandlerError(NANO_REQUEST_ERROR_HANDLER_BAD_REQUEST, "bad i_request", self)
        self.avatar = bool(self.payload.get("i_avatar"))

    async def _execute_internal(self) -> dict:
        return {
            "debug": "echo_internal",
            "account_id": self.account_id,
            "room_id": self.room_id,
            "request": self.request,
        }

    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 AbstractDocumentNanoServerHandler._execute_initial(self)
        if self.request:
            d["result"] = await self.helper.get_internal_response(
                self.account_id, self.room_id, self.request, load_avatar_name=self.avatar
            )
        else:
            d["result"] = {
                "context": await self.helper.get_internal_auth_context(
                    self.account_id, self.room_id, load_avatar_name=self.avatar
                )
            }
        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:
        if self.request:
            return "Debug internal request"
        return "Debug internal auth info"

    def build_error_message(self, buf: StringIO) -> None:
        buf.write("Debug internal request" if self.payload.get("i_request") else "Debug internal auth info")


class DebugStoreWopiTemplateHandler(AbstractDocumentNanoServerHandler):
    EXECUTION_STATE_CAN_CONFLICT = False  # cacheable and request_key are constant, no conflict is possible

    HANDLER_KEY = "debug-store-wopi-tmpl"

    def __init__(
        self, helper: DocumentServerHandleHelper, extracted_config: DocumentServerConfig, context: dict, payload: dict
    ):
        AbstractDocumentNanoServerHandler.__init__(self, helper, extracted_config, context, payload)
        self.file_path = self.payload.get("file_path")
        self.template = self.helper.validate_template_source_path(
            self.payload.get("templ_by_path") or self.file_path, self.payload.get("tmpl")
        )

    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 AbstractDocumentNanoServerHandler._execute_initial(self)
        if self.template:
            self.helper.store_template_source(
                self.file_path,
                self.context[NanoRequestContext.ACCOUNT_ID],
                self.context[NanoRequestContext.ROOM][NanoRequestContext.ROOM_ID],
                self.template,
            )
        d["result"] = self.template
        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 "Debug store wopi template"

    def build_error_message(self, buf: StringIO) -> None:
        buf.write("Debug store wopi template")
