use nom::number::streaming::be_u16;

use crate::core::parser::name::{Name, be_name};

#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct Srv {
    priority: u16,
    weight: u16,
    port: u16,
    target: Name,
}

impl Srv {
    pub fn new(priority: u16, weight: u16, port: u16, target: Name) -> Self {
        Self {
            priority,
            weight,
            port,
            target,
        }
    }

    pub fn priority(&self) -> u16 {
        self.priority
    }

    pub fn weight(&self) -> u16 {
        self.weight
    }

    pub fn port(&self) -> u16 {
        self.port
    }

    pub fn target(&self) -> &Name {
        &self.target
    }
}

pub fn be_srv<'a>(input: &'a [u8], origin: &'a [u8]) -> nom::IResult<&'a [u8], Srv> {
    let (remain, priority) = be_u16(input)?;
    let (remain, weight) = be_u16(remain)?;
    let (remain, port) = be_u16(remain)?;
    let (remain, target) = be_name(remain, origin)?;
    Ok((
        remain,
        Srv {
            priority,
            weight,
            port,
            target,
        },
    ))
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::core::parser::{
        packet::be_packet,
        question::{QueryClass, QueryType},
        record::{Class, RData},
    };
    #[test]
    fn parse_response() {
        let response = b"[\xd9\x81\x80\x00\x01\x00\x05\x00\x00\x00\x00\
            \x0c_xmpp-server\x04_tcp\x05gmail\x03com\x00\x00!\x00\x01\
            \xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00 \x00\x05\x00\x00\
            \x14\x95\x0bxmpp-server\x01l\x06google\x03com\x00\xc0\x0c\x00!\
            \x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\x14\x95\
            \x04alt3\x0bxmpp-server\x01l\x06google\x03com\x00\
            \xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\
            \x14\x95\x04alt1\x0bxmpp-server\x01l\x06google\x03com\x00\
            \xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\
            \x14\x95\x04alt2\x0bxmpp-server\x01l\x06google\x03com\x00\
            \xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\
            \x14\x95\x04alt4\x0bxmpp-server\x01l\x06google\x03com\x00";

        let (_, packet) = be_packet(response).unwrap();

        assert_eq!(packet.header.id, 23513);
        assert_eq!(packet.header.questions_count, 1);
        assert!(packet.header.flags.recursion_desired());
        assert_eq!(packet.header.answers_count, 5);
        assert_eq!(packet.questions.len(), 1);
        assert_eq!(packet.questions[0].qtype, QueryType::Srv);
        assert_eq!(packet.questions[0].qclass, QueryClass::IN);
        assert_eq!(
            &packet.questions[0].name.to_string()[..],
            "_xmpp-server._tcp.gmail.com"
        );
        assert_eq!(packet.answers.len(), 5);
        let items = [
            (5, 0, 5269, "xmpp-server.l.google.com"),
            (20, 0, 5269, "alt3.xmpp-server.l.google.com"),
            (20, 0, 5269, "alt1.xmpp-server.l.google.com"),
            (20, 0, 5269, "alt2.xmpp-server.l.google.com"),
            (20, 0, 5269, "alt4.xmpp-server.l.google.com"),
        ];
        for (i, item) in items.iter().enumerate() {
            assert_eq!(
                &packet.answers[i].name.to_string()[..],
                "_xmpp-server._tcp.gmail.com"
            );
            assert_eq!(packet.answers[i].cls, Class::IN);
            assert_eq!(packet.answers[i].ttl, 900);
            match &packet.answers[i].data {
                RData::Srv(Srv {
                    priority,
                    weight,
                    port,
                    target,
                }) => {
                    assert_eq!(priority, &item.0);
                    assert_eq!(weight, &item.1);
                    assert_eq!(port, &item.2);
                    assert_eq!(target.to_string(), item.3);
                }
                _ => panic!("Wrong rdata"),
            }
        }
    }
}
