/// Ploidy level for a genotype dataset.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Ploidy {
    Haploid,
    Diploid,
    Polyploid(u8),
}

/// A compact allele representation.
///
/// Stores alleles ≤ 7 bytes inline (covers >99% of SNPs) and heap-allocates
/// only for longer indels.
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Allele {
    Inline { len: u8, buf: [u8; 7] },
    Heap(String),
}

impl Allele {
    pub fn new(s: impl AsRef<str>) -> Self {
        let s = s.as_ref();
        if s.len() <= 7 {
            let mut buf = [0u8; 7];
            buf[..s.len()].copy_from_slice(s.as_bytes());
            Self::Inline {
                len: s.len() as u8,
                buf,
            }
        } else {
            Self::Heap(s.to_owned())
        }
    }

    pub fn as_str(&self) -> &str {
        match self {
            Self::Inline { len, buf } => {
                std::str::from_utf8(&buf[..*len as usize]).unwrap_or("?")
            }
            Self::Heap(s) => s.as_str(),
        }
    }

    pub fn is_missing(&self) -> bool {
        matches!(self.as_str(), "." | "*" | "N" | "0" | "")
    }

    pub fn len(&self) -> usize {
        match self {
            Self::Inline { len, .. } => *len as usize,
            Self::Heap(s) => s.len(),
        }
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

impl From<String> for Allele {
    fn from(s: String) -> Self {
        Self::new(&s)
    }
}

impl From<&str> for Allele {
    fn from(s: &str) -> Self {
        Self::new(s)
    }
}

impl std::fmt::Debug for Allele {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Allele(\"{}\")", self.as_str())
    }
}

impl std::fmt::Display for Allele {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.as_str())
    }
}
