"""
Type annotations for awscrt.mqtt5 module.

Copyright 2024 Vlad Emelianov
"""

from concurrent.futures import Future
from dataclasses import dataclass
from enum import IntEnum
from typing import Any, Callable, Sequence

from awscrt import NativeResource as NativeResource
from awscrt import exceptions as exceptions
from awscrt.exceptions import AwsCrtError
from awscrt.http import HttpProxyOptions as HttpProxyOptions
from awscrt.http import HttpRequest as HttpRequest
from awscrt.io import ClientBootstrap as ClientBootstrap
from awscrt.io import ClientTlsContext as ClientTlsContext
from awscrt.io import SocketOptions as SocketOptions
from awscrt.mqtt import (
    Connection,
    ConnectReturnCode,
    OnConnectionClosedData,
    OnConnectionFailureData,
    OnConnectionSuccessData,
)
from awscrt.mqtt import QoS as Mqtt3QoS

class QoS(IntEnum):
    AT_MOST_ONCE = 0
    AT_LEAST_ONCE = 1
    EXACTLY_ONCE = 2

    def to_mqtt3(self) -> Mqtt3QoS: ...

class ConnectReasonCode(IntEnum):
    SUCCESS = 0
    UNSPECIFIED_ERROR = 128
    MALFORMED_PACKET = 129
    PROTOCOL_ERROR = 130
    IMPLEMENTATION_SPECIFIC_ERROR = 131
    UNSUPPORTED_PROTOCOL_VERSION = 132
    CLIENT_IDENTIFIER_NOT_VALID = 133
    BAD_USERNAME_OR_PASSWORD = 134
    NOT_AUTHORIZED = 135
    SERVER_UNAVAILABLE = 136
    SERVER_BUSY = 137
    BANNED = 138
    BAD_AUTHENTICATION_METHOD = 140
    TOPIC_NAME_INVALID = 144
    PACKET_TOO_LARGE = 149
    QUOTA_EXCEEDED = 151
    PAYLOAD_FORMAT_INVALID = 153
    RETAIN_NOT_SUPPORTED = 154
    QOS_NOT_SUPPORTED = 155
    USE_ANOTHER_SERVER = 156
    SERVER_MOVED = 157
    CONNECTION_RATE_EXCEEDED = 159

class DisconnectReasonCode(IntEnum):
    NORMAL_DISCONNECTION = 0
    DISCONNECT_WITH_WILL_MESSAGE = 4
    UNSPECIFIED_ERROR = 128
    MALFORMED_PACKET = 129
    PROTOCOL_ERROR = 130
    IMPLEMENTATION_SPECIFIC_ERROR = 131
    NOT_AUTHORIZED = 135
    SERVER_BUSY = 137
    SERVER_SHUTTING_DOWN = 139
    KEEP_ALIVE_TIMEOUT = 141
    SESSION_TAKEN_OVER = 142
    TOPIC_FILTER_INVALID = 143
    TOPIC_NAME_INVALID = 144
    RECEIVE_MAXIMUM_EXCEEDED = 147
    TOPIC_ALIAS_INVALID = 148
    PACKET_TOO_LARGE = 149
    MESSAGE_RATE_TOO_HIGH = 150
    QUOTA_EXCEEDED = 151
    ADMINISTRATIVE_ACTION = 152
    PAYLOAD_FORMAT_INVALID = 153
    RETAIN_NOT_SUPPORTED = 154
    QOS_NOT_SUPPORTED = 155
    USE_ANOTHER_SERVER = 156
    SERVER_MOVED = 157
    SHARED_SUBSCRIPTIONS_NOT_SUPPORTED = 158
    CONNECTION_RATE_EXCEEDED = 159
    MAXIMUM_CONNECT_TIME = 160
    SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED = 161
    WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED = 162

class PubackReasonCode(IntEnum):
    SUCCESS = 0
    NO_MATCHING_SUBSCRIBERS = 16
    UNSPECIFIED_ERROR = 128
    IMPLEMENTATION_SPECIFIC_ERROR = 131
    NOT_AUTHORIZED = 135
    TOPIC_NAME_INVALID = 144
    PACKET_IDENTIFIER_IN_USE = 145
    QUOTA_EXCEEDED = 151
    PAYLOAD_FORMAT_INVALID = 153

class SubackReasonCode(IntEnum):
    GRANTED_QOS_0 = 0
    GRANTED_QOS_1 = 1
    GRANTED_QOS_2 = 2
    UNSPECIFIED_ERROR = 128
    IMPLEMENTATION_SPECIFIC_ERROR = 131
    NOT_AUTHORIZED = 135
    TOPIC_FILTER_INVALID = 143
    PACKET_IDENTIFIER_IN_USE = 145
    QUOTA_EXCEEDED = 151
    SHARED_SUBSCRIPTIONS_NOT_SUPPORTED = 158
    SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED = 161
    WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED = 162

class UnsubackReasonCode(IntEnum):
    SUCCESS = 0
    NO_SUBSCRIPTION_EXISTED = 17
    UNSPECIFIED_ERROR = 128
    IMPLEMENTATION_SPECIFIC_ERROR = 131
    NOT_AUTHORIZED = 135
    TOPIC_FILTER_INVALID = 143
    PACKET_IDENTIFIER_IN_USE = 145

class ClientSessionBehaviorType(IntEnum):
    DEFAULT = 0
    CLEAN = 1
    REJOIN_POST_SUCCESS = 2
    REJOIN_ALWAYS = 3

class PayloadFormatIndicator(IntEnum):
    AWS_MQTT5_PFI_BYTES = 0
    AWS_MQTT5_PFI_UTF8 = 1

class RetainHandlingType(IntEnum):
    SEND_ON_SUBSCRIBE = 0
    SEND_ON_SUBSCRIBE_IF_NEW = 1
    DONT_SEND = 2

class RetainAndHandlingType(IntEnum):
    SEND_ON_SUBSCRIBE = 0
    SEND_ON_SUBSCRIBE_IF_NEW = 1
    DONT_SEND = 2

class ExtendedValidationAndFlowControlOptions(IntEnum):
    NONE = 0
    AWS_IOT_CORE_DEFAULTS = 1

class ClientOperationQueueBehaviorType(IntEnum):
    DEFAULT = 0
    FAIL_NON_QOS1_PUBLISH_ON_DISCONNECT = 1
    FAIL_QOS0_PUBLISH_ON_DISCONNECT = 2
    FAIL_ALL_ON_DISCONNECT = 3

class ExponentialBackoffJitterMode(IntEnum):
    DEFAULT = 0
    NONE = 1
    FULL = 2
    DECORRELATED = 3

@dataclass
class UserProperty:
    name: str | None = ...
    value: str | None = ...

class OutboundTopicAliasBehaviorType(IntEnum):
    DEFAULT = 0
    MANUAL = 1
    LRU = 2
    DISABLED = 3

class InboundTopicAliasBehaviorType(IntEnum):
    DEFAULT = 0
    ENABLED = 1
    DISABLED = 2

@dataclass
class TopicAliasingOptions:
    outbound_behavior: OutboundTopicAliasBehaviorType | None = ...
    outbound_cache_max_size: int | None = ...
    inbound_behavior: InboundTopicAliasBehaviorType | None = ...
    inbound_cache_max_size: int | None = ...

@dataclass
class NegotiatedSettings:
    maximum_qos: QoS | None = ...
    session_expiry_interval_sec: int | None = ...
    receive_maximum_from_server: int | None = ...
    maximum_packet_size_to_server: int | None = ...
    topic_alias_maximum_to_server: int | None = ...
    topic_alias_maximum_to_client: int | None = ...
    server_keep_alive_sec: int | None = ...
    retain_available: bool | None = ...
    wildcard_subscriptions_available: bool | None = ...
    subscription_identifiers_available: bool | None = ...
    shared_subscriptions_available: bool | None = ...
    rejoined_session: bool | None = ...
    client_id: str | None = ...

@dataclass
class ConnackPacket:
    session_present: bool | None = ...
    reason_code: ConnectReasonCode | None = ...
    session_expiry_interval_sec: int | None = ...
    receive_maximum: int | None = ...
    maximum_qos: QoS | None = ...
    retain_available: bool | None = ...
    maximum_packet_size: int | None = ...
    assigned_client_identifier: str | None = ...
    topic_alias_maximum: int | None = ...
    reason_string: str | None = ...
    user_properties: Sequence[UserProperty] | None = ...
    wildcard_subscriptions_available: bool | None = ...
    subscription_identifiers_available: bool | None = ...
    shared_subscription_available: bool | None = ...
    server_keep_alive_sec: int | None = ...
    response_information: str | None = ...
    server_reference: str | None = ...

    @property
    def server_keep_alive(self) -> int | None: ...
    @server_keep_alive.setter
    def server_keep_alive(self, value: int | None) -> None: ...

@dataclass
class DisconnectPacket:
    reason_code: DisconnectReasonCode | None = ...
    session_expiry_interval_sec: int | None = ...
    reason_string: str | None = ...
    user_properties: Sequence[UserProperty] | None = ...
    server_reference: str | None = ...

@dataclass
class Subscription:
    topic_filter: str
    qos: QoS | None = ...
    no_local: bool | None = ...
    retain_as_published: bool | None = ...
    retain_handling_type: RetainAndHandlingType | RetainHandlingType | None = ...

@dataclass
class SubscribePacket:
    subscriptions: Sequence[Subscription]
    subscription_identifier: int | None = ...
    user_properties: Sequence[UserProperty] | None = ...

@dataclass
class SubackPacket:
    reason_string: str | None = ...
    user_properties: Sequence[UserProperty] | None = ...
    reason_codes: Sequence[SubackReasonCode] | None = ...

@dataclass
class UnsubscribePacket:
    topic_filters: Sequence[str]
    user_properties: Sequence[UserProperty] | None = ...

@dataclass
class UnsubackPacket:
    reason_string: str | None = ...
    user_properties: Sequence[UserProperty] | None = ...
    reason_codes: Sequence[DisconnectReasonCode] | None = ...

@dataclass
class PublishPacket:
    payload: Any | None = ...
    qos: QoS | None = ...
    retain: bool | None = ...
    topic: str | None = ...
    payload_format_indicator: PayloadFormatIndicator | None = ...
    message_expiry_interval_sec: int | None = ...
    topic_alias: int | None = ...
    response_topic: str | None = ...
    correlation_data_bytes: bytes | str | None = ...
    correlation_data: Any | None = ...
    subscription_identifiers: Sequence[int] | None = ...
    content_type: str | None = ...
    user_properties: Sequence[UserProperty] | None = ...

@dataclass
class PubackPacket:
    reason_code: PubackReasonCode | None = ...
    reason_string: str | None = ...
    user_properties: Sequence[UserProperty] | None = ...

@dataclass
class ConnectPacket:
    keep_alive_interval_sec: int | None = ...
    client_id: str | None = ...
    username: str | None = ...
    password: str | None = ...
    session_expiry_interval_sec: int | None = ...
    request_response_information: bool | None = ...
    request_problem_information: bool | None = ...
    receive_maximum: int | None = ...
    maximum_packet_size: int | None = ...
    will_delay_interval_sec: int | None = ...
    will: PublishPacket | None = ...
    user_properties: Sequence[UserProperty] | None = ...

class WebsocketHandshakeTransformArgs:
    def __init__(self, client: Client, http_request: HttpRequest, done_future: Future[Any]) -> None:
        self.client: Client
        self.http_request: HttpRequest

    def set_done(self, exception: Exception | None = ...) -> None: ...

@dataclass
class PublishReceivedData:
    publish_packet: PublishPacket | None = ...

@dataclass
class OperationStatisticsData:
    incomplete_operation_count: int = ...
    incomplete_operation_size: int = ...
    unacked_operation_count: int = ...
    unacked_operation_size: int = ...

@dataclass
class LifecycleStoppedData: ...

@dataclass
class LifecycleAttemptingConnectData: ...

@dataclass
class LifecycleConnectSuccessData:
    connack_packet: ConnackPacket | None = ...
    negotiated_settings: NegotiatedSettings | None = ...

@dataclass
class LifecycleConnectFailureData:
    connack_packet: ConnackPacket | None = ...
    exception: Exception | None = ...

@dataclass
class LifecycleDisconnectData:
    disconnect_packet: DisconnectPacket | None = ...
    exception: Exception | None = ...

@dataclass
class PublishCompletionData:
    puback: PubackPacket | None = ...

@dataclass
class ClientOptions:
    host_name: str
    port: int | None = ...
    bootstrap: ClientBootstrap | None = ...
    socket_options: SocketOptions | None = ...
    tls_ctx: ClientTlsContext | None = ...
    http_proxy_options: HttpProxyOptions | None = ...
    websocket_handshake_transform: Callable[[WebsocketHandshakeTransformArgs], None] | None = ...
    connect_options: ConnectPacket | None = ...
    session_behavior: ClientSessionBehaviorType | None = ...
    extended_validation_and_flow_control_options: (
        ExtendedValidationAndFlowControlOptions | None
    ) = ...
    offline_queue_behavior: ClientOperationQueueBehaviorType | None = ...
    retry_jitter_mode: ExponentialBackoffJitterMode | None = ...
    min_reconnect_delay_ms: int | None = ...
    max_reconnect_delay_ms: int | None = ...
    min_connected_time_to_reset_reconnect_delay_ms: int | None = ...
    ping_timeout_ms: int | None = ...
    connack_timeout_ms: int | None = ...
    ack_timeout_sec: int | None = ...
    topic_aliasing_options: TopicAliasingOptions | None = ...
    on_publish_callback_fn: Callable[[PublishReceivedData], None] | None = ...
    on_lifecycle_event_stopped_fn: Callable[[LifecycleStoppedData], None] | None = ...
    on_lifecycle_event_attempting_connect_fn: (
        Callable[[LifecycleAttemptingConnectData], None] | None
    ) = ...
    on_lifecycle_event_connection_success_fn: (
        Callable[[LifecycleConnectSuccessData], None] | None
    ) = ...
    on_lifecycle_event_connection_failure_fn: (
        Callable[[LifecycleConnectFailureData], None] | None
    ) = ...
    on_lifecycle_event_disconnection_fn: Callable[[LifecycleDisconnectData], None] | None = ...

class _ClientCore:
    def __init__(self, client_options: ClientOptions) -> None: ...

class Client(NativeResource):
    def __init__(self, client_options: ClientOptions) -> None: ...
    def start(self) -> None: ...
    def stop(self, disconnect_packet: DisconnectPacket | None = ...) -> None: ...
    def publish(self, publish_packet: PublishPacket) -> Future[PublishCompletionData]: ...
    def subscribe(self, subscribe_packet: SubscribePacket) -> Future[SubackPacket]: ...
    def unsubscribe(self, unsubscribe_packet: UnsubscribePacket) -> Future[UnsubackPacket]: ...
    def get_stats(self) -> Future[OperationStatisticsData]: ...
    def new_connection(
        self,
        on_connection_interrupted: Callable[[Connection, AwsCrtError], None] | None = ...,
        on_connection_resumed: Callable[[Connection, ConnectReturnCode, bool], None] | None = ...,
        on_connection_success: Callable[[Connection, OnConnectionSuccessData], None] | None = ...,
        on_connection_failure: Callable[[Connection, OnConnectionFailureData], None] | None = ...,
        on_connection_closed: Callable[[Connection, OnConnectionClosedData], None] | None = ...,
    ) -> Connection: ...
