"""Error types for the RouterOS Python client library."""

from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from routeros.sentence import Sentence


class RouterOSError(Exception):
    """Base exception for all RouterOS client errors."""


class DeviceError(RouterOSError):
    """Error received from the RouterOS device (!trap or !fatal sentence)."""

    def __init__(self, sentence: "Sentence") -> None:
        self.sentence = sentence
        super().__init__(self._fetch_message())

    def _fetch_message(self) -> str:
        msg = self.sentence.map.get("message", "")
        if msg:
            return msg
        return f"unknown error: {self.sentence}"

    @property
    def message(self) -> str:
        return self._fetch_message()


class UnknownReplyError(RouterOSError):
    """Received a sentence with an unrecognised Word."""

    def __init__(self, sentence: "Sentence") -> None:
        self.sentence = sentence
        super().__init__(f"unknown RouterOS reply word: {sentence.word!r}")


class LoginError(RouterOSError):
    """Authentication failed."""


# Raised when async_start() is called twice.
class AlreadyAsyncError(RouterOSError):
    """async_start() has already been called on this client."""

    def __init__(self) -> None:
        super().__init__("async_start() has already been called")


# Raised when the async loop has ended (e.g. read error) and a new
# tagged request cannot be registered.
class AsyncLoopEndedError(RouterOSError):
    """The async loop has ended – probably a read error occurred."""

    def __init__(self) -> None:
        super().__init__("async loop has ended – probably a read error occurred")


class NoChallengeReceivedError(LoginError):
    """No ret (challenge) field received during login."""

    def __init__(self) -> None:
        super().__init__("no ret (challenge) received from device")


class InvalidChallengeReceivedError(LoginError):
    """ret field received during login was not valid hex."""

    def __init__(self, detail: str = "") -> None:
        msg = "invalid ret (challenge) hex string received"
        if detail:
            msg = f"{msg}: {detail}"
        super().__init__(msg)
