mod blockquote;
mod callout;
mod code_block;
mod footnote_definition;
mod heading;
mod html_block;
mod link_definition;
mod list;
mod paragraph;
mod table;
mod thematic_break;

#[cfg(test)]
mod tests;

use nom::{IResult, Parser, branch::alt, combinator::map, sequence::preceded};

use crate::{
    ast::Block,
    parser::util::{eof_or_eol, line_terminated, many_empty_lines0},
};

pub(super) fn block<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, Vec<Block>> {
    move |input: &'a str| {
        preceded(
            many_empty_lines0,
            alt((
                map(code_block::code_block(), Block::CodeBlock),
                map(heading::heading_v1(), Block::Heading),
                heading::heading_v2_or_paragraph(),
                map(thematic_break::thematic_break(), |()| Block::ThematicBreak),
                map(callout::callout(), Block::Callout),
                map(blockquote::blockquote(), Block::BlockQuote),
                map(list::list(), Block::List),
                map(html_block::html_block(), |s| Block::HtmlBlock(s.to_owned())),
                // Alway try before link definition
                map(
                    footnote_definition::footnote_definition(),
                    Block::FootnoteDefinition,
                ),
                map(link_definition::link_definition(), Block::Definition),
                map(table::table(), Block::Table),
                map(paragraph::paragraph(false), Block::Paragraph),
            ))
            .map(|v| vec![v]),
        )
        .parse(input)
    }
}
