//! NetworkManager D-Bus interface bindings.
//!
//! Upstream documentation: <https://networkmanager.dev/docs/api/latest/>

use std::collections::HashMap;

use color_eyre::Result;
use serde::Deserialize;
use zbus::proxy;
use zbus::zvariant::{ObjectPath, OwnedValue, Str};

#[proxy(
    default_service = "org.freedesktop.NetworkManager",
    interface = "org.freedesktop.NetworkManager",
    default_path = "/org/freedesktop/NetworkManager"
)]
pub trait Dbus {
    #[zbus(property)]
    fn active_connections(&self) -> Result<Vec<ObjectPath<'_>>>;

    #[zbus(property)]
    fn devices(&self) -> Result<Vec<ObjectPath<'_>>>;

    // #[zbus(property)]
    // fn networking_enabled(&self) -> Result<bool>;

    // #[zbus(property)]
    // fn primary_connection(&self) -> Result<ObjectPath>;

    // #[zbus(property)]
    // fn primary_connection_type(&self) -> Result<Str>;

    // #[zbus(property)]
    // fn wireless_enabled(&self) -> Result<bool>;
}

#[proxy(
    default_service = "org.freedesktop.NetworkManager",
    interface = "org.freedesktop.NetworkManager.Connection.Active"
)]
pub trait ActiveConnectionDbus {
    // #[zbus(property)]
    // fn connection(&self) -> Result<ObjectPath>;

    // #[zbus(property)]
    // fn default(&self) -> Result<bool>;

    // #[zbus(property)]
    // fn default6(&self) -> Result<bool>;

    #[zbus(property)]
    fn devices(&self) -> Result<Vec<ObjectPath<'_>>>;

    // #[zbus(property)]
    // fn id(&self) -> Result<Str>;

    #[zbus(property)]
    fn type_(&self) -> Result<Str<'_>>;

    // #[zbus(property)]
    // fn uuid(&self) -> Result<Str>;
}

#[proxy(
    default_service = "org.freedesktop.NetworkManager",
    interface = "org.freedesktop.NetworkManager.Device"
)]
pub trait DeviceDbus {
    // #[zbus(property)]
    // fn active_connection(&self) -> Result<ObjectPath>;

    #[zbus(property)]
    fn device_type(&self) -> Result<DeviceType>;

    // #[zbus(property)]
    // fn path(&self) -> Result<ObjectPath<'_>>;

    #[zbus(property)]
    fn state(&self) -> Result<DeviceState>;

    #[zbus(property)]
    fn interface(&self) -> Result<Str<'_>>;

    #[zbus(property)]
    fn ip4_config(&self) -> Result<ObjectPath<'_>>;
}

#[proxy(
    default_service = "org.freedesktop.NetworkManager",
    interface = "org.freedesktop.NetworkManager.Device.Wireless"
)]
pub trait DeviceWirelessDbus {
    #[zbus(property)]
    fn active_access_point(&self) -> zbus::Result<zbus::zvariant::OwnedObjectPath>;
}

// based on code generated by `zbus-xmlgen system org.freedesktop.NetworkManager /org/freedesktop/NetworkManager/AccessPoint/1`
#[proxy(
    default_service = "org.freedesktop.NetworkManager",
    interface = "org.freedesktop.NetworkManager.AccessPoint"
)]
pub trait AccessPointDbus {
    // #[zbus(property)]
    // fn path(&self) -> Result<ObjectPath>;

    #[zbus(property)]
    fn ssid(&self) -> zbus::Result<Vec<u8>>;

    #[zbus(property)]
    fn strength(&self) -> Result<u8>;

    #[zbus(property)]
    fn hw_address(&self) -> Result<Str<'_>>;
}

// based on code generated by `zbus-xmlgen system org.freedesktop.NetworkManager /org/freedesktop/NetworkManager/AccessPoint/1`
#[proxy(
    default_service = "org.freedesktop.NetworkManager",
    interface = "org.freedesktop.NetworkManager.IP4Config"
)]
pub trait Ip4ConfigDbus {
    #[zbus(property)]
    fn address_data(&self) -> Result<Vec<HashMap<String, OwnedValue>>>;
}

/// Indicate the type of hardware represented by a device object.
///
/// See: <https://networkmanager.dev/docs/api/latest/nm-dbus-types.html#NMDeviceType>
#[derive(Clone, Copy, Debug, OwnedValue, PartialEq, Deserialize)]
#[repr(u32)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(feature = "extras", derive(schemars::JsonSchema))]
pub enum DeviceType {
    /// unknown device
    Unknown = 0,
    /// a wired ethernet device
    Ethernet = 1,
    /// an 802.11 Wi-Fi device
    Wifi = 2,
    /// not used
    Unused1 = 3,
    /// not used
    Unused2 = 4,
    /// a Bluetooth device supporting PAN or DUN access protocols
    Bt = 5,
    /// an OLPC XO mesh networking device
    OlpcMesh = 6,
    /// an 802.16e Mobile WiMAX broadband device
    Wimax = 7,
    /// a modem supporting analog telephone, CDMA/EVDO, GSM/UMTS, or LTE network access protocols
    Modem = 8,
    /// an IP-over-InfiniBand device
    Infiniband = 9,
    /// a bond controller interface
    Bond = 10,
    /// an 802.1Q VLAN interface
    Vlan = 11,
    /// ADSL modem
    Adsl = 12,
    /// a bridge controller interface
    Bridge = 13,
    /// generic support for unrecognized device types
    Generic = 14,
    /// a team controller interface
    Team = 15,
    /// a TUN or TAP interface
    Tun = 16,
    /// an IP tunnel interface
    IpTunnel = 17,
    /// a MACVLAN interface
    Macvlan = 18,
    /// a VXLAN interface
    Vxlan = 19,
    /// a VETH interface
    Veth = 20,
    /// a MACsec interface
    Macsec = 21,
    /// a dummy interface
    Dummy = 22,
    /// a PPP interface
    Ppp = 23,
    /// an Open vSwitch interface
    OvsInterface = 24,
    /// an Open vSwitch port
    OvsPort = 25,
    /// an Open vSwitch bridge
    OvsBridge = 26,
    /// a IEEE 802.15.4 (WPAN) MAC Layer Device
    Wpan = 27,
    /// 6LoWPAN interface
    SixLowpan = 28,
    /// a WireGuard interface
    Wireguard = 29,
    /// an 802.11 Wi-Fi P2P device
    WifiP2p = 30,
    /// a VRF (Virtual Routing and Forwarding) interface
    Vrf = 31,
    /// a loopback interface
    Loopback = 32,
    /// a HSR/PRP device
    Hsr = 33,
    /// an IPVLAN device
    Ipvlan = 34,
}

/// See: <https://people.freedesktop.org/~lkundrak/nm-docs/nm-dbus-types.html#NMDeviceState>
#[derive(Clone, Copy, Debug, OwnedValue, PartialEq, Eq)]
#[repr(u32)]
pub enum DeviceState {
    /// The device's state is unknown
    Unknown = 0,
    /// The device is recognized, but not managed by NetworkManager
    Unmanaged = 10,
    /// The device is managed by NetworkManager, but is not available for use. Reasons may include
    /// the wireless switched off, missing firmware, no ethernet carrier, missing supplicant or
    /// modem manager, etc.
    Unavailable = 20,
    /// The device can be activated, but is currently idle and not connected to a network.
    Disconnected = 30,
    /// The device is preparing the connection to the network. This may include operations like
    /// changing the MAC address, setting physical link properties, and anything else required to
    /// connect to the requested network.
    Prepare = 40,
    /// The device is connecting to the requested network. This may include operations like
    /// associating with the WiFi AP, dialing the modem, connecting to the remote Bluetooth device,
    /// etc.
    Config = 50,
    /// The device requires more information to continue connecting to the requested network. This
    /// includes secrets like WiFi passphrases, login passwords, PIN codes, etc.<LeftMouse>
    NeedAuth = 60,
    /// The device is requesting IPv4 and/or IPv6 addresses and routing information from the
    /// network.
    IpConfig = 70,
    /// The device is checking whether further action is required for the requested network
    /// connection. This may include checking whether only local network access is available,
    /// whether a captive portal is blocking access to the Internet, etc.
    IpCheck = 80,
    /// The device is waiting for a secondary connection (like a VPN) which must activated before
    /// the device can be activated
    Secondaries = 90,
    /// The device has a network connection, either local or global.
    Activated = 100,
    /// T disconnection from the current network connection was requested, and the device is
    /// cleaning up resources used for that connection. The network connection may still be valid.
    Deactivating = 110,
    /// The device failed to connect to the requested network and is cleaning up the connection
    /// request
    Failed = 120,
}
