Documentation
use crate::PrettyPrint;
use alloc::borrow::Cow;
use core::fmt::{Debug, Formatter};
use pretty::{
    termcolor::{Color, ColorSpec},
    Arena, DocAllocator, DocBuilder, Pretty,
};

pub type PrettyTree<'a> = DocBuilder<'a, Arena<'a, ColorSpec>, ColorSpec>;

pub struct PrettyProvider<'a> {
    arena: Arena<'a, ColorSpec>,
    keyword: ColorSpec,
}

impl<'a> Debug for PrettyProvider<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
        f.debug_struct("PrettyProvider").finish()
    }
}

impl<'a> PrettyProvider<'a> {
    pub fn new() -> Self {
        PrettyProvider { arena: Arena::new(), keyword: ColorSpec::new().set_fg(Some(Color::Rgb(197, 119, 207))).clone() }
    }
}

impl<'a> PrettyProvider<'a>
where
    'a: 'static,
{
    pub fn nil(&'a self) -> PrettyTree<'a> {
        self.arena.nil()
    }
    pub fn space(&'a self) -> PrettyTree<'a> {
        self.arena.space()
    }
    pub fn hardline(&'a self) -> PrettyTree<'a> {
        self.arena.hardline()
    }
    pub fn text<S>(&'a self, text: S) -> PrettyTree<'a>
    where
        S: Into<Cow<'static, str>>,
    {
        self.arena.text(text)
    }
    pub fn keyword<S>(&'a self, text: S) -> PrettyTree<'a>
    where
        S: Into<Cow<'static, str>>,
    {
        self.text(text.into()).annotate(self.keyword.clone())
    }
    pub fn identifier<S>(&'a self, text: S) -> PrettyTree<'a>
    where
        S: Into<Cow<'static, str>>,
    {
        self.operator(text)
    }
    pub fn generic<S>(&'a self, text: S) -> PrettyTree<'a>
    where
        S: Into<Cow<'static, str>>,
    {
        self.text(text.into()).annotate(self.macro_style())
    }
    pub fn argument<S>(&'a self, text: S) -> PrettyTree<'a>
    where
        S: Into<Cow<'static, str>>,
    {
        let kw = ColorSpec::new().set_fg(Some(Color::Rgb(239, 112, 117))).clone();
        self.text(text.into()).annotate(kw)
    }
    pub fn operator<S>(&'a self, text: S) -> PrettyTree<'a>
    where
        S: Into<Cow<'static, str>>,
    {
        let kw = ColorSpec::new().set_fg(Some(Color::Rgb(90, 173, 238))).clone();
        self.text(text.into()).annotate(kw)
    }
    pub fn string_style(&self) -> ColorSpec {
        ColorSpec::new().set_fg(Some(Color::Rgb(152, 195, 121))).clone()
    }
    pub fn number_style(&self) -> ColorSpec {
        ColorSpec::new().set_fg(Some(Color::Rgb(206, 153, 100))).clone()
    }
    pub fn macro_style(&self) -> ColorSpec {
        ColorSpec::new().set_fg(Some(Color::Rgb(87, 182, 194))).clone()
    }
}

impl<'a> PrettyProvider<'a> {
    /// Allocate a document concatenating the given documents.
    #[inline]
    pub fn concat<I>(&'a self, docs: I) -> PrettyTree<'a>
    where
        I: IntoIterator,
        I::Item: Pretty<'a, Arena<'a, ColorSpec>, ColorSpec>,
    {
        self.arena.concat(docs)
    }
    /// Allocate a document that intersperses the given separator `S` between the given documents
    /// `[A, B, C, ..., Z]`, yielding `[A, S, B, S, C, S, ..., S, Z]`.
    ///
    /// Compare [the `intersperse` method from the `itertools` crate](https://docs.rs/itertools/0.5.9/itertools/trait.Itertools.html#method.intersperse).
    ///
    /// NOTE: The separator type, `S` may need to be cloned. Consider using cheaply cloneable ptr
    /// like `RefDoc` or `RcDoc`
    #[inline]
    pub fn intersperse<T, S>(&'a self, terms: &[T], joint: S) -> PrettyTree<'a>
    where
        T: PrettyPrint,
        S: Pretty<'a, Arena<'a, ColorSpec>, ColorSpec> + Clone,
    {
        self.arena.intersperse(terms.iter().map(|x| x.build(self)), joint)
    }
    /// Allocate a document that intersperses the given separator `S` between the given documents
    /// `[A, B, C, ..., Z]`, yielding `[A, S, B, S, C, S, ..., S, Z]`.
    ///
    /// Compare [the `intersperse` method from the `itertools` crate](https://docs.rs/itertools/0.5.9/itertools/trait.Itertools.html#method.intersperse).
    ///
    /// NOTE: The separator type, `S` may need to be cloned. Consider using cheaply cloneable ptr
    /// like `RefDoc` or `RcDoc`
    #[inline]
    pub fn join<T, S>(&'a self, terms: &[T], joint: &'static str) -> PrettyTree<'a>
    where
        T: PrettyPrint,
        S: Pretty<'a, Arena<'a, ColorSpec>, ColorSpec> + Clone,
    {
        self.arena.intersperse(terms.iter().map(|x| x.build(self)), self.arena.text(joint))
    }
}