// ----- Type Explanation -----
// StrSml
// - StrSml is a string type that is used to store a small string.
// - Char count [1 byte], String Data [2 byte * Char count],
//
// - Stores a string with a maximum length of 255 characters, supporting utf-16 characters.

// ----- Structure -----
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct StrSml {
    data: Vec<u8>,
}

// ----- Conversion: From -----

use std::convert::TryFrom;

impl TryFrom<&str> for StrSml {
    type Error = &'static str;

    fn try_from(value: &str) -> Result<Self, Self::Error> {
        // Convert the string to UTF-16 code units
        let utf16_units: Vec<u16> = value.encode_utf16().collect();
        let char_count = utf16_units.len();

        // Ensure the string does not exceed the maximum length of 255 characters
        if char_count > 255 {
            return Err("String is too long");
        }

        // Prepare the data vector: 1 byte for char count, 2 bytes per UTF-16 unit
        let mut data = Vec::with_capacity(1 + char_count * 2);
        data.push(char_count as u8); // Add the char count as the first byte
        for unit in utf16_units {
            data.extend_from_slice(&unit.to_le_bytes());
        }

        Ok(Self { data })
    }
}

impl TryFrom<Vec<u8>> for StrSml {
    type Error = &'static str;

    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
        if value.is_empty() {
            return Err("Data is empty");
        }

        // Extract the character count from the first byte
        let char_count = value[0] as usize;

        // Validate the remaining length
        if value.len() != 1 + char_count * 2 {
            return Err("Invalid string data");
        }

        Ok(Self { data: value })
    }
}

// ----- Conversion: To -----

impl StrSml {
    pub fn to_string(&self) -> String {
        let char_count = self.data[0] as usize;
        let mut utf16_units = Vec::with_capacity(char_count);

        for i in 0..char_count {
            let start = 1 + i * 2;
            let unit = u16::from_le_bytes([self.data[start], self.data[start + 1]]);
            utf16_units.push(unit);
        }

        String::from_utf16(&utf16_units).unwrap()
    }

    pub fn to_vec(&self) -> Vec<u8> {
        self.data.clone()
    }
}

// ----- Getters -----

impl StrSml {
    pub fn get_len(&self) -> usize {
        self.data[0] as usize
    }

    pub fn get_data(&self) -> Vec<u8> {
        self.data.clone()
    }

    pub fn get_bytecount(&self) -> usize {
        self.data.len()
    }
}

// ----- Byte Conversion -----
impl StrSml {
    pub fn to_bytes(&self) -> &[u8] {
        &self.data
    }

    pub fn from_bytes(bytes: &[u8]) -> Self {
        Self { data: bytes.to_vec() }
    }
}

// ----- Display / Debug -----
use std::fmt;

impl fmt::Display for StrSml {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}

impl fmt::Debug for StrSml {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "StrLrg: {}", self.to_string())
    }
}