use serde::{Deserialize, Serialize};

use manta_backend_dispatcher::types::{
  Component as FrontEndComponent,
  ComponentArrayPostArray as FrontEndComponentArrayPostArray,
  ComponentCreate as FrontEndComponentCreate,
  NodeMetadataArray as FrontEndNodeMetadataArray,
};

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ComponentArray {
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename = "Components")]
  pub components: Option<Vec<Component>>,
}

impl From<FrontEndNodeMetadataArray> for ComponentArray {
  fn from(value: FrontEndNodeMetadataArray) -> Self {
    let component_vec_opt: Option<Vec<Component>> =
      if let Some(components) = value.components {
        let mut component_vec: Vec<Component> =
          Vec::with_capacity(components.len());

        components
          .into_iter()
          .for_each(|component: FrontEndComponent| {
            component_vec.push(Component::from(component))
          });

        Some(component_vec)
      } else {
        None
      };

    ComponentArray {
      components: component_vec_opt,
    }
  }
}

impl Into<FrontEndNodeMetadataArray> for ComponentArray {
  fn into(self) -> FrontEndNodeMetadataArray {
    let component_vec_opt: Option<Vec<FrontEndComponent>> =
      if let Some(components) = self.components {
        let mut component_vec: Vec<FrontEndComponent> =
          Vec::with_capacity(components.len());

        components.into_iter().for_each(|component: Component| {
          component_vec.push(component.into())
        });

        Some(component_vec)
      } else {
        None
      };

    FrontEndNodeMetadataArray {
      components: component_vec_opt,
    }
  }
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Component {
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename = "ID")]
  pub id: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename = "Type")]
  pub r#type: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename = "State")]
  pub state: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename = "Flag")]
  pub flag: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename = "Enabled")]
  pub enabled: Option<bool>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename = "SoftwareStatus")]
  pub software_status: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename = "Role")]
  pub role: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename = "SubRole")]
  pub sub_role: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename = "NID")]
  pub nid: Option<usize>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename = "Subtype")]
  pub subtype: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename = "NetType")]
  pub net_type: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename = "Arch")]
  pub arch: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename = "Class")]
  pub class: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename = "ReservationDisabled")]
  pub reservation_disabled: Option<bool>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename = "Locked")]
  pub locked: Option<bool>,
}

impl From<FrontEndComponent> for Component {
  fn from(value: FrontEndComponent) -> Self {
    Component {
      id: value.id,
      r#type: value.r#type,
      state: value.state,
      flag: value.flag,
      enabled: value.enabled,
      software_status: value.software_status,
      role: value.role,
      sub_role: value.sub_role,
      nid: value.nid,
      subtype: value.subtype,
      net_type: value.net_type,
      arch: value.arch,
      class: value.class,
      reservation_disabled: value.reservation_disabled,
      locked: value.locked,
    }
  }
}

impl Into<FrontEndComponent> for Component {
  fn into(self) -> FrontEndComponent {
    FrontEndComponent {
      id: self.id,
      r#type: self.r#type,
      state: self.state,
      flag: self.flag,
      enabled: self.enabled,
      software_status: self.software_status,
      role: self.role,
      sub_role: self.sub_role,
      nid: self.nid,
      subtype: self.subtype,
      net_type: self.net_type,
      arch: self.arch,
      class: self.class,
      reservation_disabled: self.reservation_disabled,
      locked: self.locked,
    }
  }
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ComponentArrayPostQuery {
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "ComponentIDs"))]
  pub component_ids: Option<Vec<String>>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub partition: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub group: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "stateonly"))]
  pub state_only: Option<bool>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "flagonly"))]
  pub falg_only: Option<bool>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "roleonly"))]
  pub role_only: Option<bool>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "nidonly"))]
  pub nid_only: Option<bool>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub r#type: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub state: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub flag: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub enabled: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "softwarestatus"))]
  pub software_status: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub role: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub subrole: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub subtype: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub arch: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub class: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub nid: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub nid_start: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub nid_end: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ComponentArrayPostByNidQuery {
  #[serde(rename(serialize = "NIDRanges"))]
  pub nid_ranges: Vec<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub partition: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "stateonly"))]
  pub state_only: Option<bool>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "flagonly"))]
  pub falg_only: Option<bool>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "roleonly"))]
  pub role_only: Option<bool>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "nidonly"))]
  pub nid_only: Option<bool>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ComponentArrayPostArray {
  #[serde(rename(serialize = "Components"))]
  pub components: Vec<ComponentCreate>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "Force"))]
  pub force: Option<bool>,
}

impl From<FrontEndComponentArrayPostArray> for ComponentArrayPostArray {
  fn from(value: FrontEndComponentArrayPostArray) -> Self {
    let mut component_vec: Vec<ComponentCreate> =
      Vec::with_capacity(value.components.len());

    value
      .components
      .into_iter()
      .for_each(|c| component_vec.push(c.into()));

    ComponentArrayPostArray {
      components: component_vec,
      force: value.force,
    }
  }
}

impl Into<FrontEndComponentArrayPostArray> for ComponentArrayPostArray {
  fn into(self) -> FrontEndComponentArrayPostArray {
    let mut component_vec: Vec<FrontEndComponentCreate> =
      Vec::with_capacity(self.components.len());

    self
      .components
      .into_iter()
      .for_each(|c| component_vec.push(c.into()));

    FrontEndComponentArrayPostArray {
      components: component_vec,
      force: self.force,
    }
  }
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ComponentCreate {
  #[serde(rename(serialize = "ID"))]
  id: String,
  #[serde(rename(serialize = "State"))]
  state: String,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "Flag"))]
  flag: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "Enabled"))]
  enabled: Option<bool>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "SoftwareStatus"))]
  software_status: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "Role"))]
  role: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "SubRole"))]
  sub_role: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "NID"))]
  nid: Option<usize>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "Subtype"))]
  subtype: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "NetType"))]
  net_type: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "Arch"))]
  arch: Option<String>,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "Class"))]
  class: Option<String>,
}

impl From<FrontEndComponentCreate> for ComponentCreate {
  fn from(value: FrontEndComponentCreate) -> Self {
    ComponentCreate {
      id: value.id,
      state: value.state,
      flag: value.flag,
      enabled: value.enabled,
      software_status: value.software_status,
      role: value.role,
      sub_role: value.sub_role,
      nid: value.nid,
      subtype: value.subtype,
      net_type: value.net_type,
      arch: value.arch,
      class: value.class,
    }
  }
}

impl Into<FrontEndComponentCreate> for ComponentCreate {
  fn into(self) -> FrontEndComponentCreate {
    FrontEndComponentCreate {
      id: self.id,
      state: self.state,
      flag: self.flag,
      enabled: self.enabled,
      software_status: self.software_status,
      role: self.role,
      sub_role: self.sub_role,
      nid: self.nid,
      subtype: self.subtype,
      net_type: self.net_type,
      arch: self.arch,
      class: self.class,
    }
  }
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ComponentPut {
  component: ComponentCreate,
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(rename(serialize = "Force"))]
  force: Option<bool>,
}
