from datetime import datetime

from google.protobuf.timestamp_pb2 import Timestamp

from maps_adv.warden.proto.errors_pb2 import Error

__all__ = [
    "WardenClientException",
    "BadGateway",
    "ExecutorIdAlreadyUsed",
    "GatewayTimeout",
    "InternalServerError",
    "TooEarlyForNewTask",
    "Conflict",
    "StatusSequenceViolation",
    "TaskInProgressByAnotherExecutor",
    "TaskTypeAlreadyAssigned",
    "UnknownTaskOrType",
    "UpdateStatusToInitial",
    "ValidationError",
    "UnknownResponse",
    "UnknownResponseBody",
    "UnknownError",
    "UnknownWardenStatus",
]


def proto_to_dt(proto_dt: Timestamp) -> datetime:
    return datetime.utcfromtimestamp(proto_dt.seconds)


class WardenClientException(Exception):
    pass


class BadGateway(WardenClientException):
    pass


class ExecutorIdAlreadyUsed(WardenClientException):
    pass


class GatewayTimeout(WardenClientException):
    pass


class InternalServerError(WardenClientException):
    pass


class TooEarlyForNewTask(WardenClientException):
    def __init__(self, next_try_proto_dt: Timestamp):
        self.next_try_dt = proto_to_dt(next_try_proto_dt)

        super().__init__(
            f"Try to start new task after "
            f"{self.next_try_dt.strftime('%Y-%m-%d %H:%M:%S')}"
        )


class Conflict(WardenClientException):
    pass


class StatusSequenceViolation(WardenClientException):
    pass


class TaskInProgressByAnotherExecutor(WardenClientException):
    pass


class TaskTypeAlreadyAssigned(WardenClientException):
    pass


class UnknownTaskOrType(WardenClientException):
    pass


class UpdateStatusToInitial(WardenClientException):
    pass


class ValidationError(WardenClientException):
    pass


class UnknownResponse(WardenClientException):
    def __init__(self, status_code: int, payload: bytes):
        super().__init__(f"Status={status_code}, payload={payload}")

        self.status_code = status_code
        self.payload = payload


class UnknownResponseBody(UnknownResponse):
    pass


class UnknownError(WardenClientException):
    def __init__(self, status_code: int, error: Error):
        super().__init__(
            f"Status={status_code}, error_code={error.code}, "
            f"description={error.description}"
        )

        self.status_code = status_code
        self.error = error


class UnknownWardenStatus(WardenClientException):
    def __init__(self, status: str):
        super().__init__(f"Status={status}")
        self.status = status
