use yaserde_derive::{YaDeserialize, YaSerialize};

use yaserde::MaybeString;

#[derive(Default, PartialEq, Debug, YaDeserialize, YaSerialize)]
pub struct Interface {
    pub internal_dynamic: Option<MaybeString>,
    #[yaserde(rename = "if")]
    pub physical_interface_name: String,
    pub descr: Option<MaybeString>,
    pub enable: MaybeString,
    pub lock: Option<MaybeString>,
    #[yaserde(rename = "spoofmac")]
    pub spoof_mac: Option<MaybeString>,
    pub ipaddr: Option<MaybeString>,
    pub dhcphostname: Option<MaybeString>,
    #[yaserde(rename = "alias-address")]
    pub alias_address: Option<MaybeString>,
    #[yaserde(rename = "alias-subnet")]
    pub alias_subnet: Option<MaybeString>,
    #[yaserde(rename = "blockpriv")]
    pub block_priv: Option<MaybeString>,
    #[yaserde(rename = "blockbogons")]
    pub block_bogons: Option<MaybeString>,
    #[yaserde(rename = "type")]
    pub r#type: Option<MaybeString>,
    #[yaserde(rename = "virtual")]
    pub r#virtual: Option<MaybeString>,
    pub subnet: Option<MaybeString>,
    pub ipaddrv6: Option<MaybeString>,
    #[yaserde(rename = "dhcp6-ia-pd-len")]
    pub dhcp6_ia_pd_len: Option<MaybeString>,
    pub networks: Option<MaybeString>,
    pub subnetv6: Option<MaybeString>,
    pub gateway: Option<MaybeString>,
    pub gatewayv6: Option<MaybeString>,
    pub media: Option<MaybeString>,
    pub mediaopt: Option<MaybeString>,
    #[yaserde(rename = "track6-interface")]
    pub track6_interface: Option<MaybeString>,
    #[yaserde(rename = "track6-prefix-id")]
    pub track6_prefix_id: Option<MaybeString>,
    #[yaserde(rename = "dhcprejectfrom")]
    pub dhcprejectfrom: Option<MaybeString>,
    pub adv_dhcp6_interface_statement_send_options: Option<MaybeString>,
    pub adv_dhcp6_interface_statement_request_options: Option<MaybeString>,
    pub adv_dhcp6_interface_statement_information_only_enable: Option<MaybeString>,
    pub adv_dhcp6_interface_statement_script: Option<MaybeString>,
    pub adv_dhcp6_id_assoc_statement_address_enable: Option<MaybeString>,
    pub adv_dhcp6_id_assoc_statement_address: Option<MaybeString>,
    pub adv_dhcp6_id_assoc_statement_address_id: Option<MaybeString>,
    pub adv_dhcp6_id_assoc_statement_address_pltime: Option<MaybeString>,
    pub adv_dhcp6_id_assoc_statement_address_vltime: Option<MaybeString>,
    pub adv_dhcp6_id_assoc_statement_prefix_enable: Option<MaybeString>,
    pub adv_dhcp6_id_assoc_statement_prefix: Option<MaybeString>,
    pub adv_dhcp6_id_assoc_statement_prefix_id: Option<MaybeString>,
    pub adv_dhcp6_id_assoc_statement_prefix_pltime: Option<MaybeString>,
    pub adv_dhcp6_id_assoc_statement_prefix_vltime: Option<MaybeString>,
    pub adv_dhcp6_prefix_interface_statement_sla_len: Option<MaybeString>,
    pub adv_dhcp6_authentication_statement_authname: Option<MaybeString>,
    pub adv_dhcp6_authentication_statement_protocol: Option<MaybeString>,
    pub adv_dhcp6_authentication_statement_algorithm: Option<MaybeString>,
    pub adv_dhcp6_authentication_statement_rdm: Option<MaybeString>,
    pub adv_dhcp6_key_info_statement_keyname: Option<MaybeString>,
    pub adv_dhcp6_key_info_statement_realm: Option<MaybeString>,
    pub adv_dhcp6_key_info_statement_keyid: Option<MaybeString>,
    pub adv_dhcp6_key_info_statement_secret: Option<MaybeString>,
    pub adv_dhcp6_key_info_statement_expire: Option<MaybeString>,
    pub adv_dhcp6_config_advanced: Option<MaybeString>,
    pub adv_dhcp6_config_file_override: Option<MaybeString>,
    pub adv_dhcp6_config_file_override_path: Option<MaybeString>,
    pub adv_dhcp_pt_timeout: Option<MaybeString>,
    pub adv_dhcp_pt_retry: Option<MaybeString>,
    pub adv_dhcp_pt_select_timeout: Option<MaybeString>,
    pub adv_dhcp_pt_reboot: Option<MaybeString>,
    pub adv_dhcp_pt_backoff_cutoff: Option<MaybeString>,
    pub adv_dhcp_pt_initial_interval: Option<MaybeString>,
    pub adv_dhcp_pt_values: Option<MaybeString>,
    pub adv_dhcp_send_options: Option<MaybeString>,
    pub adv_dhcp_request_options: Option<MaybeString>,
    pub adv_dhcp_required_options: Option<MaybeString>,
    pub adv_dhcp_option_modifiers: Option<MaybeString>,
    pub adv_dhcp_config_advanced: Option<MaybeString>,
    pub adv_dhcp_config_file_override: Option<MaybeString>,
    pub adv_dhcp_config_file_override_path: Option<MaybeString>,
}

#[cfg(test)]
mod test {
    use crate::xml_utils::to_xml_str;

    use super::*;
    use pretty_assertions::assert_eq;
    use yaserde::NamedList;

    #[derive(Default, PartialEq, Debug, YaDeserialize, YaSerialize)]
    pub struct InterfacesParent {
        foo: String,
        interfaces: NamedList<Interface>,
        bar: String,
    }

    #[test]
    fn should_deserialize_interfaces() {
        let interfaces =
            yaserde::de::from_str::<NamedList<Interface>>(FULL_INTERFACES_XML).unwrap();
        assert_eq!(interfaces.elements.len(), 6)
    }

    #[test]
    fn should_serialize_interfaces() {
        let named_list = NamedList {
            elements: vec![
                (String::from("paul"), Interface::default()),
                (String::from("anotherpaul"), Interface::default()),
                (String::from("thirdone"), Interface::default()),
                (String::from("andgofor4"), Interface::default()),
            ],
        };

        let parent = InterfacesParent {
            foo: String::from("foo"),
            interfaces: named_list,
            bar: String::from("foo"),
        };

        assert_eq!(
            &to_xml_str(&parent).unwrap(),
            r#"<?xml version="1.0"?>
<InterfacesParent>
  <foo>foo</foo>
  <interfaces>
    <paul>
      <if></if>
      <enable/>
    </paul>
    <anotherpaul>
      <if></if>
      <enable/>
    </anotherpaul>
    <thirdone>
      <if></if>
      <enable/>
    </thirdone>
    <andgofor4>
      <if></if>
      <enable/>
    </andgofor4>
  </interfaces>
  <bar>foo</bar>
</InterfacesParent>
"#
        )
    }

    const FULL_INTERFACES_XML: &str = "<interfaces>
    <lan>
      <if>em1</if>
      <descr>LAN</descr>
      <enable>1</enable>
      <spoofmac/>
      <media/>
      <mediaopt/>
      <ipaddr>192.168.20.1</ipaddr>
      <subnet>24</subnet>
      <ipaddrv6>track6</ipaddrv6>
      <track6-interface/>
      <track6-prefix-id>0</track6-prefix-id>
    </lan>
    <wan>
      <if>pppoe0</if>
      <descr>WAN</descr>
      <enable>1</enable>
      <lock>1</lock>
      <spoofmac/>
      <blockpriv>1</blockpriv>
      <blockbogons>1</blockbogons>
      <ipaddr>pppoe</ipaddr>
    </wan>
    <lo0>
      <internal_dynamic>1</internal_dynamic>
      <descr>Loopback</descr>
      <enable>1</enable>
      <if>lo0</if>
      <ipaddr>127.0.0.1</ipaddr>
      <ipaddrv6>::1</ipaddrv6>
      <subnet>8</subnet>
      <subnetv6>128</subnetv6>
      <type>none</type>
      <virtual>1</virtual>
    </lo0>
    <opt1>
      <if>em5</if>
      <descr>backup_sync</descr>
      <enable>1</enable>
      <lock>1</lock>
      <spoofmac/>
      <ipaddr>10.10.5.1</ipaddr>
      <subnet>24</subnet>
    </opt1>
    <wireguard>
      <internal_dynamic>1</internal_dynamic>
      <descr>WireGuard (Group)</descr>
      <if>wireguard</if>
      <virtual>1</virtual>
      <enable>1</enable>
      <type>group</type>
      <networks/>
    </wireguard>
    <openvpn>
      <internal_dynamic>1</internal_dynamic>
      <enable>1</enable>
      <if>openvpn</if>
      <descr>OpenVPN</descr>
      <type>group</type>
      <virtual>1</virtual>
      <networks/>
    </openvpn>
  </interfaces>";
}
