use anyhow::Result;
use cosmic_notifications_config::PANEL_NOTIFICATIONS_FD;
use smithay::reexports::rustix::io::{FdFlags, fcntl_getfd, fcntl_setfd};
use smithay::reexports::rustix::{self};
use std::os::fd::{FromRawFd, RawFd};
use std::os::unix::net::UnixStream;
use tracing::info;
use zbus::connection::Builder;
use zbus::proxy;

#[proxy(
    default_service = "com.system76.NotificationsSocket",
    interface = "com.system76.NotificationsSocket",
    default_path = "/com/system76/NotificationsSocket"
)]
pub trait NotificationsSocket {
    /// get an fd for an applet
    fn get_fd(&self) -> zbus::Result<zbus::zvariant::OwnedFd>;
}
pub async fn notifications_conn() -> Result<NotificationsSocketProxy<'static>> {
    info!("Connecting to notifications daemon");
    let fd_num = std::env::var(PANEL_NOTIFICATIONS_FD)
        .map_err(|_| anyhow::anyhow!("No {} env var found", PANEL_NOTIFICATIONS_FD))?;
    let fd = fd_num
        .parse::<RawFd>()
        .map_err(|_| anyhow::anyhow!("Invalid {} env var", PANEL_NOTIFICATIONS_FD))?;
    let fd = unsafe { rustix::fd::OwnedFd::from_raw_fd(fd) };

    let res = fcntl_getfd(&fd).and_then(|flags| fcntl_setfd(&fd, FdFlags::CLOEXEC.union(flags)));

    let daemon_stream = match res {
        // CLOEXEC worked and we can startup with session IPC
        Ok(_) => UnixStream::from(fd),
        // CLOEXEC didn't work, something is wrong with the fd, just close it
        Err(err) => {
            return Err(err.into());
        },
    };
    daemon_stream.set_nonblocking(true)?;

    let stream = tokio::net::UnixStream::from_std(daemon_stream)?;
    let conn = Builder::socket(stream).p2p().build().await?;
    info!("Made socket connection");
    let proxy = NotificationsSocketProxy::new(&conn).await?;
    info!("Connected to notifications");

    Ok(proxy)
}
