use crate::generator::highlight::highlight;
use pulldown_cmark::{CodeBlockKind, Event, Tag};

pub fn new<'a, I: Iterator<Item = Event<'a>>>(iter: I) -> Highlight<'a, I> {
    Highlight { iter }
}

pub struct Highlight<'a, I: Iterator<Item = Event<'a>>> {
    iter: I,
}

impl<'a, I: Iterator<Item = Event<'a>>> Iterator for Highlight<'a, I> {
    type Item = Event<'a>;

    fn next(&mut self) -> Option<Event<'a>> {
        match self.iter.next() {
            Some(Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(label)))) => {
                let code = self.consume_code_block();
                let mut highlighted = highlight(&code, &label);
                highlighted.insert_str(
                    0,
                    &format!("<pre class=\"highlight\" data-lang=\"{}\"><code>", label),
                );
                highlighted.push_str("</code></pre>");
                Some(Event::Html(highlighted.into()))
            }
            e => e,
        }
    }
}

impl<'a, I: Iterator<Item = Event<'a>>> Highlight<'a, I> {
    fn consume_code_block(&mut self) -> String {
        let mut buf = String::new();
        loop {
            match self.iter.next() {
                Some(Event::End(Tag::CodeBlock(CodeBlockKind::Fenced(_)))) => {
                    break;
                }
                Some(Event::Text(s)) => {
                    buf.push_str(&s);
                }
                e => panic!("unexpected event in fenced code block: {:?}", e),
            }
        }
        buf
    }
}

#[cfg(test)]
mod tests {
    use pulldown_cmark::{html, Parser};

    fn render(s: &str) -> String {
        let mut out = String::new();
        let parser = Parser::new(s);
        let heading_anchors = super::new(parser);
        html::push_html(&mut out, heading_anchors);
        out
    }

    #[test]
    fn test_higlight_markdown() {
        assert_eq!(
            render("```js\nfoo(bar, 123)\n```".into()),
            r#"<pre class="highlight" data-lang="js"><code><span class="hl-fn">foo</span>(<span class="hl-var">bar</span>, <span class="hl-num">123</span>)
</code></pre>"#
        );
    }
}
