use crate::{Error, payload::{Decode, Encode}, Payload};
use std::io::{Read, Seek};
use byteorder::ReadBytesExt;
use crate::payload::{SeStringChunkKind, SeInteractableKind};

#[derive(Debug, Clone, PartialEq)]
pub struct DalamudLinkPayload {
    pub plugin: String,
    pub command: u32,
}

impl Decode for DalamudLinkPayload {
    fn decode<R: Read + Seek>(mut reader: R, _chunk_len: usize) -> Result<Self, Error> {
        let plugin_len = reader.read_u8().map_err(Error::from)?;
        let mut plugin_bytes = vec![0; plugin_len as usize];
        reader.read_exact(&mut plugin_bytes).map_err(Error::from)?;
        let plugin = String::from_utf8(plugin_bytes).map_err(Error::from)?;

        let command = Self::read_integer(reader)?;

        Ok(Self {
            plugin,
            command,
        })
    }
}

impl Encode for DalamudLinkPayload {
    fn encode(&self) -> Vec<u8> {
        use std::iter::once;

        let plugin = self.plugin.as_bytes();
        let command = Self::make_integer(self.command);
        let chunk_len = 3 + plugin.len() + command.len();

        // FIXME: check if chunk_len > 255

        once(Payload::START_BYTE)
            .chain(once(SeStringChunkKind::Interactable.as_u8()))
            .chain(once(chunk_len as u8))
            .chain(once(SeInteractableKind::DalamudLink.as_u8()))
            .chain(once(plugin.len() as u8))
            .chain(plugin.iter().copied())
            .chain(command.into_iter())
            .chain(once(Payload::END_BYTE))
            .collect()
    }
}
