static BASE16_HEXA_DECIMAL: u8 = 16;
static BASE16_HEXA_DECIMAL_POSSIBLE_VALUE_PER_DIGIT: u8 = 15;
static BASE16_HEXA_DECIMAL_DIGIT_BITS: u8 = 4;

pub trait EnCodable {
    fn encode(&self) -> String;
}

pub trait DeCodable {
    fn decode(&self) -> Result<Vec<u8>, ()>;
}

impl EnCodable for [u8] {
    fn encode(self: &[u8]) -> String {
        let mut result = String::with_capacity(self.len());
        let result_vec = unsafe { result.as_mut_vec() };
        self.iter().for_each(|byte| {
            if !matches!(byte, b'0'..=b'9' | b'A'..=b'Z' | b'a'..=b'z' | b'-' | b'_' | b'.' | b'~')
            {
                result_vec.push(b'%');
                result_vec.push(hex_to_digit(byte >> BASE16_HEXA_DECIMAL_DIGIT_BITS));
                result_vec.push(hex_to_digit(
                    byte & BASE16_HEXA_DECIMAL_POSSIBLE_VALUE_PER_DIGIT,
                ));
            } else {
                result_vec.push(*byte)
            }
        });
        result
    }
}
impl DeCodable for &str {
    fn decode(&self) -> Result<Vec<u8>, ()> {
        let mut first = true;
        let mut result = Vec::with_capacity(self.len());

        for i in self.split('%') {
            if first {
                first = false;
                result.extend_from_slice(i.as_bytes());
                continue;
            }
            let Ok(char) = u8::from_str_radix(i[0..2].as_ref(), BASE16_HEXA_DECIMAL.into()) else {
                    return Err(());
            };
            result.push(char);
            result.extend_from_slice(i[2..].as_bytes());
        }
        Ok(result)
    }
}

fn hex_to_digit(digit: u8) -> u8 {
    match digit {
        0..=9 => b'0' + digit,
        10..=255 => b'A' + digit - 10,
    }
}

#[cfg(test)]
mod test {
    use crate::utils::urlencoded::endecode::DeCodable;
    use crate::utils::urlencoded::endecode::EnCodable;

    #[test]
    fn urlencoded_test() {
        assert_eq!(
            "Darius%20is%20the%20biggest%20genius%2FGenie%2FHuman%20extraordin%C3%A4ire",
            b"Darius is the biggest genius/Genie/Human extraordin\xC3\xA4ire".encode()
        );
    }
    #[test]
    fn urldecoded_test() {
        assert_eq!(
            "Darius is the biggest genius/Genie/Human extraordinäire",
            String::from_utf8(
                "Darius%20is%20the%20biggest%20genius%2FGenie%2FHuman%20extraordin%C3%A4ire"
                    .decode()
                    .unwrap()
            )
            .unwrap()
        );
        assert_eq!(
            Err(()),
            "Darius%2iis%20the%20biggest%20genius%2FGenie%2FHuman%20extraordin%C3%A4ire".decode()
        );
    }
}