// ----- Type Explanation -----
// FormID
// - FormID is an ID type that is used to identify something in an efficient way.
// - Form ID [2 bytes],
//
// - Stores an id value with a maximum value of 65535.
//
// - Supports conversion from and to base 10 and hexadecimal string representations.

// ----- Structure -----

#[derive(Clone, PartialEq, Eq, Hash, Copy)]
pub struct FormID {
    data: [u8; 2],
}

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

use std::convert::TryFrom;

/// Implements conversions from various types to `FormID`.
impl TryFrom<u16> for FormID {
    type Error = &'static str;

    fn try_from(value: u16) -> Result<Self, Self::Error> {
        let data = value.to_le_bytes();
        Ok(Self { data })
    }
}

impl TryFrom<[u8; 2]> for FormID {
    type Error = &'static str;

    fn try_from(value: [u8; 2]) -> Result<Self, Self::Error> {
        Ok(Self { data: value })
    }
}

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

    fn try_from(value: &str) -> Result<Self, Self::Error> {
        let id: u16 = if value.starts_with("0x") || value.starts_with("0X") {
            // Attempt to parse as hexadecimal, stripping the "0x" or "0X" prefix
            u16::from_str_radix(&value[2..], 16).map_err(|_| "Invalid hexadecimal FormID value")?
        } else {
            // Default to base 10
            value.parse::<u16>().map_err(|_| "Invalid base 10 FormID value")?
        };

        Ok(Self { data: id.to_le_bytes() })
    }
}

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

impl FormID {
    /// Converts the internal data to a `u16`.
    pub fn to_u16(&self) -> u16 {
        u16::from_le_bytes(self.data)
    }

    /// Converts the `FormID` to a base 10 `String`, padded with leading zeroes to ensure 5 characters.
    pub fn to_string(&self) -> String {
        format!("{:0>5}", self.to_u16())
    }

    /// Converts the `FormID` to a hexadecimal `String`, prefixed with `0x`.
    pub fn to_hex(&self) -> String {
        format!("0x{:04X}", self.to_u16())
    }


}

// ----- Getters -----
impl FormID {    
    /// Returns the number of bytes in the `FormID`.
    pub fn get_bytecount(&self) -> usize {
        self.data.len()
    }
}

// ----- Byte Conversion -----
impl FormID { 
    /// Creates a `FormID` from a byte array.
    pub fn from_bytes(bytes: [u8; 2]) -> Self {
        Self { data: bytes }
    }

    /// Returns the internal byte array.
    pub fn to_bytes(&self) -> [u8; 2] {
        self.data
    }
}

// ----- Display / Debug -----

use std::fmt;

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

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