from typing import Optional, Callable

from clarabot_crypto.keyring.account_base import AbstractSelfAccountKeyring, AbstractPeerAccountKeyring
from clarabot_crypto.keyring.adhoc import AdhocKeyring
from clarabot_crypto.keyring.room_base import AbstractRoomKeyring
from clarabot_nano_common.common.protocol.nano_request import NanoResponseStreamProcessor, NanoResponseError


class TestingNanoResponseStreamProcessor(NanoResponseStreamProcessor):
    def __init__(
        self,
        raw_req: bytes,
        room_id: Optional[int],
        nano_id: Optional[int],
        req_kr: AbstractSelfAccountKeyring,
        nano_kr: AbstractPeerAccountKeyring,
        room_kr: Optional[AbstractRoomKeyring] = None,
        adhoc_kr: Optional[AdhocKeyring] = None,
        error: Optional[int] = None,  # error code from Nano
        server_error: Optional[str] = None,  # error from client server
        single_response: bool = True,
        part_delta: int = 0,
        response_handler_cb: Optional[Callable[[int, dict], None]] = None,
        cache_key: Optional[bytes] = None,
        transfer_key: Optional[bytes] = None,
    ):
        NanoResponseStreamProcessor.__init__(
            self,
            raw_req,
            req_kr,
            nano_kr,
            room_kr,
            adhoc_kr,
            single_response,
            part_delta,
            cache_key,
            transfer_key,
            response_handler_cb=response_handler_cb,
        )
        self.room_id = room_id
        self.nano_id = nano_id
        self.expected_error = error
        self.expected_server_error = server_error

    def feed(self, response: dict):
        try:
            NanoResponseStreamProcessor.feed(self, response)
        except NanoResponseError as e:
            assert False, str(e)

    def finish(self):
        if self.expected_server_error is not None:
            assert self.server_error == self.expected_server_error, f"{self.expected_server_error} {self.server_error}"
        if self.expected_error is not None:
            assert self.error == self.expected_error, f"{self.expected_error} {self.error} {self.server_error}"
        try:
            NanoResponseStreamProcessor.finish(self)
        except NanoResponseError as e:
            assert False, str(e)
