// SPDX-License-Identifier: MIT

use crate::Socket;
use std::os::unix::io::AsRawFd;

use mio::{event::Source, unix::SourceFd};

impl Source for Socket {
    fn register(
        &mut self,
        registry: &mio::Registry,
        token: mio::Token,
        interests: mio::Interest,
    ) -> std::io::Result<()> {
        let raw_fd = self.as_raw_fd();

        SourceFd(&raw_fd).register(registry, token, interests)
    }

    fn reregister(
        &mut self,
        registry: &mio::Registry,
        token: mio::Token,
        interests: mio::Interest,
    ) -> std::io::Result<()> {
        let raw_fd = self.as_raw_fd();

        SourceFd(&raw_fd).reregister(registry, token, interests)
    }

    fn deregister(&mut self, registry: &mio::Registry) -> std::io::Result<()> {
        let raw_fd = self.as_raw_fd();

        SourceFd(&raw_fd).deregister(registry)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    fn request_neighbour_dump(socket: &mut Socket) -> std::io::Result<()> {
        // Buffer generated from:
        // ```
        // let mut neighbour_dump_request = NetlinkMessage {
        //     header: NetlinkHeader {
        //         flags: NLM_F_DUMP | NLM_F_REQUEST,
        //         ..Default::default()
        //     },
        //     payload: NetlinkPayload::from(RtnlMessage::GetNeighbour(NeighbourMessage::default())),
        // };
        // ```
        let buf = [
            28, 0, 0, 0, 30, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0,
        ];
        socket.send(&buf[..], 0)?;

        Ok(())
    }

    #[test]
    fn test_event_loop() -> Result<(), Box<dyn std::error::Error>> {
        use crate::{protocols::NETLINK_ROUTE, Socket, SocketAddr};
        use mio::{Events, Interest, Poll, Token};
        use std::time::Duration;

        let mut poll = Poll::new()?;
        let mut events = Events::with_capacity(128);

        let mut socket = Socket::new(NETLINK_ROUTE)?;
        socket.bind_auto()?;
        socket.connect(&SocketAddr::new(0, 0))?;
        poll.registry()
            .register(&mut socket, Token(1), Interest::READABLE)?;

        // Send neighbour query
        request_neighbour_dump(&mut socket)?;

        // Make sure that we got anything
        poll.poll(&mut events, Some(Duration::from_secs(1)))?;
        assert!(!events.is_empty());

        // Make sure the we didn't get a thing after removing socket from loop
        poll.registry().deregister(&mut socket)?;
        poll.poll(&mut events, Some(Duration::from_secs(1)))?;
        assert!(events.is_empty());

        Ok(())
    }
}
