use crate::internal::as2_pcode::parser::Tokens;
use annotate_snippets::renderer::DecorStyle;
use annotate_snippets::{AnnotationKind, Renderer};
use winnow::error::{ContextError, ParseError};

#[derive(Debug)]
pub struct PCodeError<'a> {
    filename: &'a str,
    source: &'a str,
    error: ParseError<Tokens<'a>, ContextError>,
}

impl<'a> PCodeError<'a> {
    pub(crate) fn from_parse(
        filename: &'a str,
        source: &'a str,
        error: ParseError<Tokens<'a>, ContextError>,
    ) -> Self {
        Self {
            filename,
            source,
            error,
        }
    }
}

impl std::fmt::Display for PCodeError<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let tokens = self.error.input();
        let mut source = annotate_snippets::Snippet::source(self.source).path(self.filename);
        if let Some(bad_token) = tokens.get(self.error.offset()) {
            source = source
                .annotation(AnnotationKind::Primary.span(bad_token.span.start..bad_token.span.end));
        }
        let report = &[annotate_snippets::Level::ERROR
            .primary_title(self.error.inner().to_string())
            .element(source)];
        let renderer = Renderer::styled().decor_style(DecorStyle::Unicode);
        renderer.render(report).fmt(f)
    }
}

impl std::error::Error for PCodeError<'_> {}
