use std::borrow::Cow;
use std::fmt::{Debug, Display, Write};
use std::ops::Deref;
use std::str::FromStr;
use std::sync::Arc;
use serde::{Deserialize, Serialize};
#[derive(Hash, PartialEq, Eq, Deserialize, Serialize, Debug, Clone, Ord, PartialOrd)]
#[serde(try_from = "String")]
#[serde(into = "String")]
pub struct Name {
    name: Arc<Cow<'static, str>>,
    needs_escaping: bool,
}
#[derive(thiserror::Error, Debug, Serialize, Deserialize, Clone)]
#[error("invalid name: {0}")]
pub struct InvalidNameError(pub String);
impl Name {
    pub fn new<T: Into<Self>>(contents: T) -> Self {
        contents.into()
    }
    pub fn parse_encoded(encoded: &str) -> Result<Self, InvalidNameError> {
        let mut bytes = encoded.bytes();
        let mut decoded = Vec::with_capacity(encoded.len());
        while let Some(byte) = bytes.next() {
            if byte == b'_' {
                if let (Some(high), Some(low)) = (bytes.next(), bytes.next()) {
                    if let Some(byte) = hex_chars_to_byte(high, low) {
                        decoded.push(byte);
                        continue;
                    }
                }
                return Err(InvalidNameError(encoded.to_string()));
            }
            decoded.push(byte);
        }
        String::from_utf8(decoded)
            .map(Self::from)
            .map_err(|_| InvalidNameError(encoded.to_string()))
    }
    #[must_use]
    pub fn encoded(&self) -> String {
        format!("{self:#}")
    }
}
impl From<Cow<'static, str>> for Name {
    fn from(value: Cow<'static, str>) -> Self {
        let needs_escaping = !value
            .bytes()
            .all(|b| b.is_ascii_alphanumeric() || b == b'-');
        Self {
            name: Arc::new(value),
            needs_escaping,
        }
    }
}
impl From<&'static str> for Name {
    fn from(value: &'static str) -> Self {
        Self::from(Cow::Borrowed(value))
    }
}
impl From<String> for Name {
    fn from(value: String) -> Self {
        Self::from(Cow::Owned(value))
    }
}
#[allow(clippy::from_over_into)] impl Into<String> for Name {
    fn into(self) -> String {
        self.name.to_string()
    }
}
impl Display for Name {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        if f.alternate() && self.needs_escaping {
            for byte in self.name.bytes() {
                if byte.is_ascii_alphanumeric() || byte == b'-' {
                    f.write_char(byte as char)?;
                } else {
                    f.write_char('_')?;
                    f.write_char(nibble_to_hex_char(byte >> 4))?;
                    f.write_char(nibble_to_hex_char(byte & 0xF))?;
                }
            }
            Ok(())
        } else {
            Display::fmt(&self.name, f)
        }
    }
}
const fn nibble_to_hex_char(nibble: u8) -> char {
    let ch = match nibble {
        0..=9 => b'0' + nibble,
        _ => b'a' + nibble - 10,
    };
    ch as char
}
const fn hex_chars_to_byte(high_nibble: u8, low_nibble: u8) -> Option<u8> {
    match (
        hex_char_to_nibble(high_nibble),
        hex_char_to_nibble(low_nibble),
    ) {
        (Some(high_nibble), Some(low_nibble)) => Some(high_nibble << 4 | low_nibble),
        _ => None,
    }
}
const fn hex_char_to_nibble(nibble: u8) -> Option<u8> {
    let ch = match nibble {
        b'0'..=b'9' => nibble - b'0',
        b'a'..=b'f' => nibble - b'a' + 10,
        _ => return None,
    };
    Some(ch)
}
impl AsRef<str> for Name {
    fn as_ref(&self) -> &str {
        self.name.as_ref()
    }
}
#[derive(Hash, PartialEq, Eq, Deserialize, Serialize, Debug, Clone, Ord, PartialOrd)]
#[serde(transparent)]
pub struct Authority(Name);
impl From<Cow<'static, str>> for Authority {
    fn from(value: Cow<'static, str>) -> Self {
        Self::from(Name::from(value))
    }
}
impl From<&'static str> for Authority {
    fn from(value: &'static str) -> Self {
        Self::from(Cow::Borrowed(value))
    }
}
impl From<String> for Authority {
    fn from(value: String) -> Self {
        Self::from(Cow::Owned(value))
    }
}
impl From<Name> for Authority {
    fn from(value: Name) -> Self {
        Self(value)
    }
}
impl Display for Authority {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        Display::fmt(&self.0, f)
    }
}
impl AsRef<str> for Authority {
    fn as_ref(&self) -> &str {
        self.0.as_ref()
    }
}
#[derive(Hash, PartialEq, Eq, Deserialize, Serialize, Debug, Clone, Ord, PartialOrd)]
pub struct QualifiedName {
    pub authority: Authority,
    pub name: Name,
}
impl Display for QualifiedName {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        Display::fmt(&self.authority, f)?;
        f.write_char('.')?;
        Display::fmt(&self.name, f)
    }
}
impl FromStr for QualifiedName {
    type Err = InvalidNameError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::parse_encoded(s)
    }
}
pub trait Qualified: Display + Sized {
    #[must_use]
    fn private<N: Into<Name>>(name: N) -> Self {
        Self::new(Authority::from("private"), name)
    }
    #[must_use]
    fn new<A: Into<Authority>, N: Into<Name>>(authority: A, name: N) -> Self;
    fn parse_encoded(schema_name: &str) -> Result<Self, InvalidNameError> {
        let mut parts = schema_name.split('.');
        if let (Some(authority), Some(name), None) = (parts.next(), parts.next(), parts.next()) {
            let authority = Name::parse_encoded(authority)?;
            let name = Name::parse_encoded(name)?;
            Ok(Self::new(authority, name))
        } else {
            Err(InvalidNameError(schema_name.to_string()))
        }
    }
    #[must_use]
    fn encoded(&self) -> String {
        format!("{self:#}")
    }
}
impl Qualified for QualifiedName {
    fn new<A: Into<Authority>, N: Into<Name>>(authority: A, name: N) -> Self {
        Self {
            authority: authority.into(),
            name: name.into(),
        }
    }
}
#[derive(Hash, PartialEq, Eq, Deserialize, Serialize, Debug, Clone, Ord, PartialOrd)]
#[serde(transparent)]
pub struct SchemaName(pub(crate) QualifiedName);
impl Qualified for SchemaName {
    fn new<A: Into<Authority>, N: Into<Name>>(authority: A, name: N) -> Self {
        Self(QualifiedName::new(authority, name))
    }
}
impl Display for SchemaName {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        Display::fmt(&self.0, f)
    }
}
impl Deref for SchemaName {
    type Target = QualifiedName;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
impl From<CollectionName> for SchemaName {
    fn from(name: CollectionName) -> Self {
        Self(name.0)
    }
}
impl FromStr for SchemaName {
    type Err = InvalidNameError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::parse_encoded(s)
    }
}
#[derive(Hash, PartialEq, Eq, Deserialize, Serialize, Debug, Clone, Ord, PartialOrd)]
#[serde(transparent)]
pub struct CollectionName(pub(crate) QualifiedName);
impl Qualified for CollectionName {
    fn new<A: Into<Authority>, N: Into<Name>>(authority: A, name: N) -> Self {
        Self(QualifiedName::new(authority, name))
    }
}
impl Display for CollectionName {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        Display::fmt(&self.0, f)
    }
}
impl Deref for CollectionName {
    type Target = QualifiedName;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
impl FromStr for CollectionName {
    type Err = InvalidNameError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::parse_encoded(s)
    }
}
#[derive(Hash, PartialEq, Eq, Deserialize, Serialize, Debug, Clone, PartialOrd, Ord)]
pub struct ViewName {
    pub collection: CollectionName,
    pub name: Name,
}
impl ViewName {
    pub fn new<
        C: TryInto<CollectionName, Error = InvalidNameError>,
        N: TryInto<Name, Error = InvalidNameError>,
    >(
        collection: C,
        name: N,
    ) -> Result<Self, InvalidNameError> {
        let collection = collection.try_into()?;
        let name = name.try_into()?;
        Ok(Self { collection, name })
    }
}
impl Display for ViewName {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        Display::fmt(&self.collection, f)?;
        f.write_char('.')?;
        Display::fmt(&self.name, f)
    }
}
impl FromStr for ViewName {
    type Err = InvalidNameError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let (first, view_name) = s
            .rsplit_once('.')
            .ok_or_else(|| InvalidNameError(s.to_string()))?;
        let collection = first.parse()?;
        let name = Name::parse_encoded(view_name)?;
        Ok(Self { collection, name })
    }
}
#[test]
fn name_escaping_tests() {
    const VALID_CHARS: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-";
    const INVALID_CHARS: &str = "._hello\u{1F680}";
    const ESCAPED_INVALID: &str = "_2e_5fhello_f0_9f_9a_80";
    assert_eq!(Name::new(VALID_CHARS).to_string(), VALID_CHARS);
    assert_eq!(Name::new(INVALID_CHARS).to_string(), INVALID_CHARS);
    assert_eq!(Name::new(INVALID_CHARS).encoded(), ESCAPED_INVALID);
    assert_eq!(
        Name::parse_encoded(ESCAPED_INVALID).unwrap(),
        Name::new(INVALID_CHARS)
    );
    Name::parse_encoded("_").unwrap_err();
    Name::parse_encoded("_0").unwrap_err();
    Name::parse_encoded("_z").unwrap_err();
    Name::parse_encoded("_0z").unwrap_err();
}
#[test]
fn joined_names_tests() {
    const INVALID_CHARS: &str = "._hello\u{1F680}.._world\u{1F680}";
    const ESCAPED_INVALID: &str = "_2e_5fhello_f0_9f_9a_80._2e_5fworld_f0_9f_9a_80";
    let collection = CollectionName::parse_encoded(ESCAPED_INVALID).unwrap();
    assert_eq!(collection.to_string(), INVALID_CHARS);
    assert_eq!(collection.encoded(), ESCAPED_INVALID);
    let schema_name = SchemaName::parse_encoded(ESCAPED_INVALID).unwrap();
    assert_eq!(schema_name.to_string(), INVALID_CHARS);
    assert_eq!(schema_name.encoded(), ESCAPED_INVALID);
}