use serde::{Deserialize, Serialize};

/// Variants of option 53 in [MessageOptions](crate::v4::MessageOptions).
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[repr(u8)]
pub enum MessageTypes {
    /// Client broadcast to locate available servers.
    ///
    /// Value 1. Defined in [RFC-2132](https://datatracker.ietf.org/doc/html/rfc2131).
    Discover,
    /// Server to client in response to DHCPDISCOVER with offer of configuration parameters.
    ///
    /// Value 2. Defined in [RFC-2132](https://datatracker.ietf.org/doc/html/rfc2131).
    Offer,
    /// Client message to servers either:
    /// (a) requesting offered parameters from one server and implicitly declining offers from all others,
    /// (b) confirming correctness of previously allocated address after, e.g., system reboot, or (c) extending the lease on a particular network address.
    ///
    /// Value 3. Defined in [RFC-2132](https://datatracker.ietf.org/doc/html/rfc2131).
    Request,
    /// Client to server indicating network address is already in use.
    ///
    /// Value 4. Defined in [RFC-2132](https://datatracker.ietf.org/doc/html/rfc2131).
    Decline,
    /// Server to client with configuration parameters, including committed network address.
    ///
    /// Value 5. Defined in [RFC-2132](https://datatracker.ietf.org/doc/html/rfc2131).
    Ack,
    /// Server to client indicating client's notion of network address is incorrect (e.g., client has moved to new subnet) or client's lease as expired
    ///
    /// If the selected server is unable to satisfy the DHCPREQUEST message
    /// (example: the requested network address has been allocated), the
    /// server SHOULD respond with a DHCPNAK message.
    ///
    /// Value 6. Defined in [RFC-2132](https://datatracker.ietf.org/doc/html/rfc2131).
    Nak,
    /// Client to server relinquishing network address and cancelling remaining lease.
    ///
    /// Value 7. Defined in [RFC-2132](https://datatracker.ietf.org/doc/html/rfc2131).
    Release,
    /// Client to server, asking only for local configuration parameters; client already has externally configured network address.
    ///
    /// Value 8. Defined in [RFC-2132](https://datatracker.ietf.org/doc/html/rfc2131).
    Inform,
    /// Server to client which forces the client into the RENEW state.
    ///
    /// Value 9. Defined in [RFC-3203](https://datatracker.ietf.org/doc/html/rfc3203).
    ForceRenew,
    /// Relay agent to server asking for lease information to know the location of an IP endpoint.
    ///
    /// Value 10. Defined in [RFC-4388](https://datatracker.ietf.org/doc/html/rfc4388).
    LeaseQuery,
    /// Server to relay agent indicating that there is currently no active lease on the resultant IP
    ///  address but that this DHCP server is authoritative for this IP address.
    ///
    /// Value 11. Defined in [RFC-4388](https://datatracker.ietf.org/doc/html/rfc4388).
    LeaseUnassigned,
    /// Server to relay agent indicating that the DHCP server has no knowledge of the information
    /// specified in the query (e.g., IP address, MAC address, or Client-identifier option).
    ///
    /// Value 12. Defined in [RFC-4388](https://datatracker.ietf.org/doc/html/rfc4388).
    LeaseUnknown,
    /// Server to relay agent which allows the agent to determine the IP
    /// endpoint location and the remaining duration of the IP address lease.
    ///
    /// Value 13. Defined in [RFC-4388](https://datatracker.ietf.org/doc/html/rfc4388).
    LeaseActive,
    /// Client to server asking for information concerning existing DHCPv4 IPv4 address
    /// bindings managed by the DHCPv4 server.
    ///
    /// Value 14. Defined in [RFC-6926](https://datatracker.ietf.org/doc/html/rfc6926).
    BulkLeaseQuery,
    /// Server to client after processing the bulk query is complete.
    ///
    /// Value 15. Defined in [RFC-6926](https://datatracker.ietf.org/doc/html/rfc6926).
    LeaseQueryDone,
    /// Client to server requesting that the server sends updates whenever some
    /// activity occurs that changes the binding state.
    ///
    /// Value 16. Defined in [RFC-7724](https://datatracker.ietf.org/doc/html/rfc7724) which updates RFC-6926.
    ActiveLeaseQuery,
    /// Server to client. May unilaterally terminate a successful ActiveLeaseQuery request, that is currently in
    /// progress, in the event that the server determines that it cannot continue processing it. For example,
    /// when a server is requested to shut down, it should send a LeaseQueryStatus message with a dhcp-status-code
    /// of `QueryTerminated` and include in the message a base-time. This must be the last message on that connection,
    /// and once the message has been transmitted, the server must close the connection.
    ///
    /// Value 17. Defined in [RFC-7724](https://datatracker.ietf.org/doc/html/rfc7724) which updates RFC-6926.
    LeaseQueryStatus,
    /// Client to server over a newly created TCP connection to request a TLS connection.
    ///
    /// If the server supports TLS connections, it must respond with a Tls message with no dhcp-status-code.
    /// If the server does not support TLS connections, it must respond with a Tls message with
    /// a dhcp-status-code of TLSConnectionRefused.
    ///
    /// Value 18. Defined in [RFC-7724](https://datatracker.ietf.org/doc/html/rfc7724) which updates RFC-6926.
    Tls,
    /// Not implemented
    Other(u8),
}

impl From<&MessageTypes> for u8 {
    fn from(mtype: &MessageTypes) -> Self {
        match mtype {
            MessageTypes::Discover => 1,
            MessageTypes::Offer => 2,
            MessageTypes::Request => 3,
            MessageTypes::Decline => 4,
            MessageTypes::Ack => 5,
            MessageTypes::Nak => 6,
            MessageTypes::Release => 7,
            MessageTypes::Inform => 8,
            MessageTypes::ForceRenew => 9,
            MessageTypes::LeaseQuery => 10,
            MessageTypes::LeaseUnassigned => 11,
            MessageTypes::LeaseUnknown => 12,
            MessageTypes::LeaseActive => 13,
            MessageTypes::BulkLeaseQuery => 14,
            MessageTypes::LeaseQueryDone => 15,
            MessageTypes::ActiveLeaseQuery => 16,
            MessageTypes::LeaseQueryStatus => 17,
            MessageTypes::Tls => 18,
            MessageTypes::Other(x) => *x,
        }
    }
}

impl From<&[u8]> for MessageTypes {
    fn from(value: &[u8]) -> Self {
        match value[0] {
            1 => MessageTypes::Discover,
            2 => MessageTypes::Offer,
            3 => MessageTypes::Request,
            4 => MessageTypes::Decline,
            5 => MessageTypes::Ack,
            6 => MessageTypes::Nak,
            7 => MessageTypes::Release,
            8 => MessageTypes::Inform,
            9 => MessageTypes::ForceRenew,
            10 => MessageTypes::LeaseQuery,
            11 => MessageTypes::LeaseUnassigned,
            12 => MessageTypes::LeaseUnknown,
            13 => MessageTypes::LeaseActive,
            14 => MessageTypes::BulkLeaseQuery,
            15 => MessageTypes::LeaseQueryDone,
            16 => MessageTypes::ActiveLeaseQuery,
            17 => MessageTypes::LeaseQueryStatus,
            18 => MessageTypes::Tls,
            x => MessageTypes::Other(x),
        }
    }
}

impl MessageTypes {
    /// Used, when serializing, to add to the byte buffer.
    #[inline]
    pub fn extend_into(&self, bytes: &mut Vec<u8>, tag: u8) {
        bytes.push(tag); // tag
        bytes.push(1); // length
        bytes.push(self.into()); // value
    }
}
