use std::{
  collections::VecDeque,
  sync::{Arc, Mutex},
};

use crate::errors::PsdkFatherResult;

use super::{ConnectedDevice, ConnectionState, DeviceWriteOptions, ReadOptions};

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FakeWrite {
  pub binary: Vec<u8>,
  pub send_done: bool,
}

#[derive(Debug)]
struct FakeConnectedDeviceState {
  device_name: String,
  device_mac: Option<String>,
  connection_state: ConnectionState,
  written_chunks: Vec<FakeWrite>,
  read_queue: VecDeque<Vec<u8>>,
  cancel_write_count: usize,
}

impl Default for FakeConnectedDeviceState {
  fn default() -> Self {
    Self {
      device_name: "FAKE-DEVICE".to_string(),
      device_mac: None,
      connection_state: ConnectionState::Connected,
      written_chunks: Vec::new(),
      read_queue: VecDeque::new(),
      cancel_write_count: 0,
    }
  }
}

#[derive(Clone, Debug)]
pub struct FakeConnectedDevice {
  state: Arc<Mutex<FakeConnectedDeviceState>>,
}

impl FakeConnectedDevice {
  pub fn new() -> Self {
    Self {
      state: Arc::new(Mutex::new(FakeConnectedDeviceState::default())),
    }
  }

  pub fn with_device_name(self, device_name: impl Into<String>) -> Self {
    {
      let mut state = self.state.lock().unwrap();
      state.device_name = device_name.into();
    }
    self
  }

  pub fn with_device_mac(self, device_mac: impl Into<String>) -> Self {
    {
      let mut state = self.state.lock().unwrap();
      state.device_mac = Some(device_mac.into());
    }
    self
  }

  pub fn with_read_data(self, read_data: Vec<Vec<u8>>) -> Self {
    {
      let mut state = self.state.lock().unwrap();
      state.read_queue = read_data.into();
    }
    self
  }

  pub fn written_chunks(&self) -> Vec<FakeWrite> {
    self.state.lock().unwrap().written_chunks.clone()
  }

  pub fn cancel_write_count(&self) -> usize {
    self.state.lock().unwrap().cancel_write_count
  }
}

impl Default for FakeConnectedDevice {
  fn default() -> Self {
    Self::new()
  }
}

impl ConnectedDevice for FakeConnectedDevice {
  fn device_name(&self) -> String {
    self.state.lock().unwrap().device_name.clone()
  }

  fn device_mac(&self) -> Option<String> {
    self.state.lock().unwrap().device_mac.clone()
  }

  fn connection_state(&self) -> ConnectionState {
    self.state.lock().unwrap().connection_state.clone()
  }

  fn disconnect(&self) -> PsdkFatherResult<()> {
    let mut state = self.state.lock().unwrap();
    state.connection_state = ConnectionState::Disconnected;
    Ok(())
  }

  fn cancel_write(&self) -> PsdkFatherResult<bool> {
    let mut state = self.state.lock().unwrap();
    state.cancel_write_count += 1;
    Ok(false)
  }

  fn can_read(&self) -> bool {
    true
  }

  fn write(&self, binary: &[u8]) -> PsdkFatherResult<()> {
    self.write_with_options(binary, DeviceWriteOptions::default())
  }

  fn write_with_options(&self, binary: &[u8], options: DeviceWriteOptions) -> PsdkFatherResult<()> {
    let mut state = self.state.lock().unwrap();
    state.written_chunks.push(FakeWrite {
      binary: binary.to_vec(),
      send_done: options.send_done,
    });
    Ok(())
  }

  fn read(&self, _options: Option<ReadOptions>) -> PsdkFatherResult<Vec<u8>> {
    Ok(
      self
        .state
        .lock()
        .unwrap()
        .read_queue
        .pop_front()
        .unwrap_or_default(),
    )
  }

  fn flush(&self) -> PsdkFatherResult<()> {
    Ok(())
  }
}
