use std::{borrow::Cow, sync::Arc};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SharedString(ArcCow<'static, str>);

impl From<String> for SharedString {
    fn from(s: String) -> Self {
        SharedString(ArcCow::Owned(Arc::from(s)))
    }
}

impl<'a> iced::advanced::text::IntoFragment<'a> for SharedString {
    fn into_fragment(self) -> Cow<'a, str> {
        match self.0 {
            ArcCow::Borrowed(b) => Cow::Borrowed(b),
            ArcCow::Owned(o) => Cow::Owned(o.as_ref().to_string()),
        }
    }
}

impl<'a> iced::advanced::text::IntoFragment<'a> for &SharedString {
    fn into_fragment(self) -> Cow<'a, str> {
        match &self.0 {
            ArcCow::Borrowed(b) => Cow::Borrowed(b),
            ArcCow::Owned(o) => Cow::Owned(o.as_ref().to_string()),
        }
    }
}

impl From<&'static str> for SharedString {
    fn from(s: &'static str) -> Self {
        SharedString(ArcCow::Borrowed(s))
    }
}

impl AsRef<str> for SharedString {
    fn as_ref(&self) -> &str {
        match &self.0 {
            ArcCow::Borrowed(b) => b,
            ArcCow::Owned(o) => o.as_ref(),
        }
    }
}

impl std::ops::Deref for SharedString {
    type Target = str;

    fn deref(&self) -> &Self::Target {
        self.as_ref()
    }
}

#[derive(Clone, PartialEq, Eq, Hash)]
pub struct SecretSharedString(ArcCow<'static, str>);

impl core::fmt::Debug for SecretSharedString {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str("(..secret..)")
    }
}

impl From<String> for SecretSharedString {
    fn from(s: String) -> Self {
        Self(ArcCow::Owned(Arc::from(s)))
    }
}

#[derive(Debug, PartialEq, Eq, Hash)]
pub enum ArcCow<'a, T: ?Sized> {
    Borrowed(&'a T),
    Owned(Arc<T>),
}

impl<'a, T> Clone for ArcCow<'a, T>
where
    T: ?Sized,
{
    fn clone(&self) -> Self {
        match self {
            ArcCow::Borrowed(b) => ArcCow::Borrowed(b),
            ArcCow::Owned(o) => ArcCow::Owned(Arc::clone(o)),
        }
    }
}

impl<'a, T> From<&'a T> for ArcCow<'a, T> {
    fn from(value: &'a T) -> Self {
        ArcCow::Borrowed(value)
    }
}
