mod autolink;
mod code_span;
mod emphasis;
mod footnote_reference;
mod hard_newline;
mod html_entity;
mod image;
mod inline_link;
mod reference_link;
mod strikethrough;
mod tag;
mod text;
mod wikilink;

#[cfg(test)]
mod tests;

use nom::{
    IResult, Parser,
    branch::alt,
    combinator::map,
    multi::{many0, many1},
};

use crate::ast::Inline;

pub(super) fn inline_many0<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, Vec<Inline>> {
    move |input: &'a str| {
        let (input, list_of_lists) = many0(inline()).parse(input)?;
        let r: Vec<_> = list_of_lists.into_iter().flatten().collect();
        Ok((input, r))
    }
}

pub(super) fn inline_many1<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, Vec<Inline>> {
    move |input: &'a str| {
        let (input, list_of_lists) = many1(inline()).parse(input)?;
        let r: Vec<_> = list_of_lists.into_iter().flatten().collect();
        Ok((input, r))
    }
}

pub(super) fn inline<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, Vec<Inline>> {
    move |input: &'a str| {
        alt((
            map(wikilink::wikilink(), Inline::Wikilink),
            map(autolink::autolink, Inline::Autolink),
            map(inline_link::inline_link(), Inline::Link),
            footnote_reference::footnote_reference,
            reference_link::reference_link(),
            hard_newline::hard_newline,
            image::image(),
            map(code_span::code_span, Inline::Code),
            emphasis::emphasis(),
            strikethrough::strikethrough(),
            map(tag::tag(), Inline::Tag),
            text::text(),
        ))
        .map(|v| vec![v])
        .parse(input)
    }
}
