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

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

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

use std::convert::TryFrom;

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

    fn try_from(value: &str) -> Result<Self, Self::Error> {
        // Ensure the string length does not exceed 255 characters
        let char_count = value.chars().count();
        if char_count > 255 {
            return Err("String is too long. Maximum 255 characters allowed.");
        }

        // Ensure all characters are ASCII (1 byte in UTF-8)
        if !value.is_ascii() {
            return Err("Non-ASCII characters detected. StrMin supports only ASCII characters.");
        }

        // Convert the string to bytes
        let string_bytes = value.as_bytes();

        // Create the data vector with the first byte as the length
        let mut data = Vec::with_capacity(1 + string_bytes.len());
        data.push(char_count as u8);
        data.extend_from_slice(string_bytes);

        Ok(Self { data })
    }
}

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

    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
        // The vector must have at least 1 byte for the length
        if value.is_empty() {
            return Err("Data is empty. Must contain at least 1 byte for length.");
        }

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

        // The remaining bytes should exactly match the character count
        if value.len() != 1 + char_count {
            return Err("Data length does not match the character count.");
        }

        // Ensure all bytes are valid ASCII
        if !value[1..].iter().all(|&b| b.is_ascii()) {
            return Err("Non-ASCII bytes detected. StrMin supports only ASCII characters.");
        }

        let data = value;

        Ok(Self { data })
    }
}

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

impl StrMin {
    /// Converts the internal data to a `String`.
    /// 
    /// # Panics
    /// 
    /// Panics if the internal data is not valid UTF-8, which should never happen
    /// as the data is validated during creation.
    pub fn to_string(&self) -> String {
        // Extract the string bytes (excluding the first byte which is the length)
        // Safe to unwrap because data is validated to be ASCII, hence valid UTF-8
        String::from_utf8(self.data[1..].to_vec()).unwrap()
    }

    /// Returns a clone of the internal byte vector.
    pub fn to_vec(&self) -> Vec<u8> {
        self.data.clone()
    }
}

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

impl StrMin {
    /// Returns the number of characters in the string.
    pub fn get_len(&self) -> usize {
        self.data.get(0).copied().unwrap_or(0) as usize
    }

    /// Returns a clone of the internal byte vector.
    pub fn get_data(&self) -> Vec<u8> {
        self.data.clone()
    }

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


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

    // return error if the byte array is not the correct length
    pub fn from_bytes(bytes: &[u8]) -> Result<Self, &'static str> {
        // The vector must have at least 1 byte for the length
        if bytes.is_empty() {
            return Err("Data is empty. Must contain at least 1 byte for length.");
        }

        // Extract the character count
        let char_count = bytes[0] as usize;

        // The remaining bytes should exactly match the character count
        if bytes.len() != 1 + char_count {
            return Err("Data length does not match the character count.");
        }

        // Ensure all bytes are valid ASCII
        if !bytes[1..].iter().all(|&b| b.is_ascii()) {
            return Err("Non-ASCII bytes detected. StrMin supports only ASCII characters.");
        }

        let data = bytes.to_vec();

        Ok(Self { data })
    }
}

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

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

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