use ntex::util::ByteString;
use std::{io, marker::PhantomData, num::NonZeroU16};
use super::codec;
use crate::{error, types::QoS};
#[derive(Debug)]
pub enum ControlMessage<E> {
    Ping(Ping),
    Disconnect(Disconnect),
    Subscribe(Subscribe),
    Unsubscribe(Unsubscribe),
    Closed(Closed),
    Error(Error<E>),
    ProtocolError(ProtocolError),
    PeerGone(PeerGone),
}
#[derive(Debug)]
pub struct ControlResult {
    pub(crate) result: ControlResultKind,
}
#[derive(Debug)]
pub(crate) enum ControlResultKind {
    Nothing,
    PublishAck(NonZeroU16),
    Ping,
    Disconnect,
    Subscribe(SubscribeResult),
    Unsubscribe(UnsubscribeResult),
    Closed,
}
impl<E> ControlMessage<E> {
    #[doc(hidden)]
    pub fn ping() -> Self {
        ControlMessage::Ping(Ping)
    }
    #[doc(hidden)]
    pub fn subscribe(pkt: Subscribe) -> Self {
        ControlMessage::Subscribe(pkt)
    }
    #[doc(hidden)]
    pub fn unsubscribe(pkt: Unsubscribe) -> Self {
        ControlMessage::Unsubscribe(pkt)
    }
    #[doc(hidden)]
    pub fn remote_disconnect() -> Self {
        ControlMessage::Disconnect(Disconnect)
    }
    pub(super) fn closed() -> Self {
        ControlMessage::Closed(Closed)
    }
    pub(super) fn error(err: E) -> Self {
        ControlMessage::Error(Error::new(err))
    }
    pub(super) fn proto_error(err: error::ProtocolError) -> Self {
        ControlMessage::ProtocolError(ProtocolError::new(err))
    }
    pub(super) fn peer_gone(err: Option<io::Error>) -> Self {
        ControlMessage::PeerGone(PeerGone(err))
    }
    pub fn disconnect(&self) -> ControlResult {
        ControlResult { result: ControlResultKind::Disconnect }
    }
}
#[derive(Copy, Clone, Debug)]
pub struct Ping;
impl Ping {
    pub fn ack(self) -> ControlResult {
        ControlResult { result: ControlResultKind::Ping }
    }
}
#[derive(Copy, Clone, Debug)]
pub struct Disconnect;
impl Disconnect {
    pub fn ack(self) -> ControlResult {
        ControlResult { result: ControlResultKind::Disconnect }
    }
}
#[derive(Debug)]
pub struct Error<E> {
    err: E,
}
impl<E> Error<E> {
    pub fn new(err: E) -> Self {
        Self { err }
    }
    #[inline]
    pub fn get_ref(&self) -> &E {
        &self.err
    }
    #[inline]
    pub fn ack(self) -> ControlResult {
        ControlResult { result: ControlResultKind::Disconnect }
    }
    #[inline]
    pub fn ack_and_error(self) -> (ControlResult, E) {
        (ControlResult { result: ControlResultKind::Disconnect }, self.err)
    }
}
#[derive(Debug)]
pub struct ProtocolError {
    err: error::ProtocolError,
}
impl ProtocolError {
    pub fn new(err: error::ProtocolError) -> Self {
        Self { err }
    }
    #[inline]
    pub fn get_ref(&self) -> &error::ProtocolError {
        &self.err
    }
    #[inline]
    pub fn ack(self) -> ControlResult {
        ControlResult { result: ControlResultKind::Disconnect }
    }
    #[inline]
    pub fn ack_and_error(self) -> (ControlResult, error::ProtocolError) {
        (ControlResult { result: ControlResultKind::Disconnect }, self.err)
    }
}
#[derive(Debug)]
pub struct Subscribe {
    packet_id: NonZeroU16,
    packet_size: u32,
    topics: Vec<(ByteString, QoS)>,
    codes: Vec<codec::SubscribeReturnCode>,
}
#[derive(Debug)]
pub(crate) struct SubscribeResult {
    pub(crate) codes: Vec<codec::SubscribeReturnCode>,
    pub(crate) packet_id: NonZeroU16,
}
impl Subscribe {
    #[doc(hidden)]
    pub fn new(
        packet_id: NonZeroU16,
        packet_size: u32,
        topics: Vec<(ByteString, QoS)>,
    ) -> Self {
        let mut codes = Vec::with_capacity(topics.len());
        (0..topics.len()).for_each(|_| codes.push(codec::SubscribeReturnCode::Failure));
        Self { packet_id, packet_size, topics, codes }
    }
    pub fn packet_size(&self) -> u32 {
        self.packet_size
    }
    #[inline]
    pub fn iter_mut(&mut self) -> SubscribeIter<'_> {
        SubscribeIter { subs: self as *const _ as *mut _, entry: 0, lt: PhantomData }
    }
    #[inline]
    pub fn ack(self) -> ControlResult {
        ControlResult {
            result: ControlResultKind::Subscribe(SubscribeResult {
                codes: self.codes,
                packet_id: self.packet_id,
            }),
        }
    }
}
impl<'a> IntoIterator for &'a mut Subscribe {
    type Item = Subscription<'a>;
    type IntoIter = SubscribeIter<'a>;
    fn into_iter(self) -> SubscribeIter<'a> {
        self.iter_mut()
    }
}
pub struct SubscribeIter<'a> {
    subs: *mut Subscribe,
    entry: usize,
    lt: PhantomData<&'a mut Subscribe>,
}
impl<'a> SubscribeIter<'a> {
    fn next_unsafe(&mut self) -> Option<Subscription<'a>> {
        let subs = unsafe { &mut *self.subs };
        if self.entry < subs.topics.len() {
            let s = Subscription {
                topic: &subs.topics[self.entry].0,
                qos: subs.topics[self.entry].1,
                code: &mut subs.codes[self.entry],
            };
            self.entry += 1;
            Some(s)
        } else {
            None
        }
    }
}
impl<'a> Iterator for SubscribeIter<'a> {
    type Item = Subscription<'a>;
    #[inline]
    fn next(&mut self) -> Option<Subscription<'a>> {
        self.next_unsafe()
    }
}
#[derive(Debug)]
pub struct Subscription<'a> {
    topic: &'a ByteString,
    qos: QoS,
    code: &'a mut codec::SubscribeReturnCode,
}
impl<'a> Subscription<'a> {
    #[inline]
    pub fn topic(&self) -> &'a ByteString {
        self.topic
    }
    #[inline]
    pub fn qos(&self) -> QoS {
        self.qos
    }
    #[inline]
    pub fn fail(&mut self) {
        *self.code = codec::SubscribeReturnCode::Failure
    }
    #[inline]
    pub fn confirm(&mut self, qos: QoS) {
        *self.code = codec::SubscribeReturnCode::Success(qos)
    }
    #[inline]
    #[doc(hidden)]
    pub fn subscribe(&mut self, qos: QoS) {
        self.confirm(qos)
    }
}
#[derive(Debug)]
pub struct Unsubscribe {
    packet_id: NonZeroU16,
    packet_size: u32,
    topics: Vec<ByteString>,
}
#[derive(Debug)]
pub(crate) struct UnsubscribeResult {
    pub(crate) packet_id: NonZeroU16,
}
impl Unsubscribe {
    #[doc(hidden)]
    pub fn new(packet_id: NonZeroU16, packet_size: u32, topics: Vec<ByteString>) -> Self {
        Self { packet_id, packet_size, topics }
    }
    pub fn packet_size(&self) -> u32 {
        self.packet_size
    }
    pub fn iter(&self) -> impl Iterator<Item = &ByteString> {
        self.topics.iter()
    }
    #[inline]
    pub fn ack(self) -> ControlResult {
        ControlResult {
            result: ControlResultKind::Unsubscribe(UnsubscribeResult {
                packet_id: self.packet_id,
            }),
        }
    }
}
#[derive(Debug)]
pub struct Closed;
impl Closed {
    #[inline]
    pub fn ack(self) -> ControlResult {
        ControlResult { result: ControlResultKind::Closed }
    }
}
#[derive(Debug)]
pub struct PeerGone(pub(super) Option<io::Error>);
impl PeerGone {
    pub fn err(&self) -> Option<&io::Error> {
        self.0.as_ref()
    }
    pub fn take(&mut self) -> Option<io::Error> {
        self.0.take()
    }
    pub fn ack(self) -> ControlResult {
        ControlResult { result: ControlResultKind::Nothing }
    }
}