//! Define the configuration of the host device.
//!
//! The constants in this module define the maximum sizes of the various buffers used during
//! communication in `kdeconnect-proto`. Each of these constants have a default value but can be
//! set using the correct environment variable.
use crate::device::DeviceType;

#[cfg(not(feature = "std"))]
use alloc::{string::String, vec::Vec};

pub(crate) const MIN_TCP_PORT: u16 = 1716;
pub(crate) const MAX_TCP_PORT: u16 = 1764;
pub(crate) const UDP_PORT: u16 = 1716;
pub(crate) const KDECONNECT_PROTOCOL_VERSION: u16 = 8;

/// The maximum size of the buffer used by UDP connections (this setting also applies for
/// MDNS buffers, although they are not shared with UDP-only connections).
///
/// Default value: 2500 bytes
/// Environment variable to set: KDECONNECT_UDP_BUFFER_SIZE
pub const UDP_BUFFER_SIZE: usize = const {
    if let Some(str_value) = option_env!("KDECONNECT_UDP_BUFFER_SIZE") {
        if let Ok(value) = usize::from_str_radix(str_value, 10) {
            value
        } else {
            panic!("Failed to parse environment variable `KDECONNECT_UDP_BUFFER_SIZE`");
        }
    } else {
        2500
    }
};

/// The maximum size of the buffer used by TCP connections.
///
/// Default value: 2500 bytes
/// Environment variable to set: KDECONNECT_TCP_BUFFER_SIZE
pub const TCP_BUFFER_SIZE: usize = const {
    if let Some(str_value) = option_env!("KDECONNECT_TCP_BUFFER_SIZE") {
        if let Ok(value) = usize::from_str_radix(str_value, 10) {
            value
        } else {
            panic!("Failed to parse environment variable `KDECONNECT_TCP_BUFFER_SIZE`");
        }
    } else {
        2500
    }
};

/// The maximum size of the buffer used by TLS connections.
///
/// Default value: 2500 bytes
/// Environment variable to set: KDECONNECT_TLS_BUFFER_SIZE
pub const TLS_BUFFER_SIZE: usize = const {
    if let Some(str_value) = option_env!("KDECONNECT_TLS_BUFFER_SIZE") {
        if let Ok(value) = usize::from_str_radix(str_value, 10) {
            value
        } else {
            panic!("Failed to parse environment variable `KDECONNECT_TLS_BUFFER_SIZE`");
        }
    } else {
        2500
    }
};

/// The maximum size of the buffer used by TLS connections of the main application.
///
/// Default value: 3000 bytes
/// Environment variable to set: KDECONNECT_TLS_APP_BUFFER_SIZE
pub const TLS_APP_BUFFER_SIZE: usize = const {
    if let Some(str_value) = option_env!("KDECONNECT_TLS_APP_BUFFER_SIZE") {
        if let Ok(value) = usize::from_str_radix(str_value, 10) {
            value
        } else {
            panic!("Failed to parse environment variable `KDECONNECT_TLS_APP_BUFFER_SIZE`");
        }
    } else {
        3000
    }
};

/// The configuration of the host device.
///
/// You must generate a self-signed certificate with the device ID as CommonName in order to start
/// a device and connect to other peers.
///
/// You can either use `openssl` to generate a certificate using:
///
/// ```bash
/// openssl req -x509 \
///     -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -keyout private_key.pem \
///     -addext basicConstraints=critical,CA:FALSE \
///     -days 3650 -nodes -subj "/O=KDE/OU=KDE Connect/CN=<your host device ID>" -out cert.pem
/// ```
///
/// Or use the `rcgen` crate:
///
/// ```ignore
/// use std::fs;
/// use rcgen::{CertificateParams, DistinguishedName, DnType, IsCa, KeyPair};
///
/// pub fn gen_certificate(uuid: &str) {
///     let mut params = CertificateParams::default();
///     params.is_ca = IsCa::ExplicitNoCa;
///
///     let mut dn = DistinguishedName::new();
///     dn.push(DnType::CommonName, uuid);
///     dn.push(DnType::OrganizationName, "KDE");
///     dn.push(DnType::OrganizationalUnitName, "KDE Connect");
///     params.distinguished_name = dn;
///
///     let key_pair = KeyPair::generate().unwrap();
///     let cert = params.self_signed(&key_pair).unwrap();
///
///     fs::write("private_key.pem", key_pair.serialize_pem()).unwrap();
///     fs::write("cert.pem", cert.pem()).unwrap();
/// }
/// ```
///
/// You can then make a [`DeviceConfig`] using the content of the files `cert.pem` and
/// `private_key.pem`, respectively in the [`DeviceConfig::cert`] and [`DeviceConfig::private_key`]
/// fields.
#[derive(Debug, Clone)]
pub struct DeviceConfig {
    /// The name of the host device.
    ///
    /// It must be 1-32 characters in length and shouldn't contain any of the following punctuation marks `"',;:.!?()[]<>`.
    pub name: String,

    /// The physical type of the host device.
    pub device_type: DeviceType,

    /// A PEM-encoded X.509 certificate.
    pub cert: Vec<u8>,

    /// A PEM-encoded X.509 private signing key.
    pub private_key: Vec<u8>,
}
