from collections.abc import Callable
import mistune
import mistune.directives
import pygments
import pygments.lexers
import pygments.formatters


class LevelAdjustingHTMLRenderer(mistune.HTMLRenderer):
    header_level_delta: int

    def __init__(self, header_level_delta: int = 0, **kwargs):
        self.header_level_delta = header_level_delta
        super().__init__(**kwargs)

    def heading(self, text: str, level: int, **attrs) -> str:
        if 1 > level + self.header_level_delta > 6:
            raise ValueError(
                f"cannot render header with level {level} as it would result in a level outside of 1 <= n <= 6"
            )
        return super().heading(text, level + self.header_level_delta, **attrs)


class SyntaxHighlightingHTMLRenderer(mistune.HTMLRenderer):
    def block_code(self, code: str, info: str | None = None) -> str:
        if info is None:
            return super().block_code(code)

        return pygments.highlight(
            code.replace("\t", "    "),
            pygments.lexers.get_lexer_by_name(info),
            pygments.formatters.HtmlFormatter(
                noclasses=True,  # Use inline styles
                nobackground=True,  # Don't set the background colour of the container
                wrapcode=True,
            ),
        )


class CustomHTMLRenderer(LevelAdjustingHTMLRenderer, SyntaxHighlightingHTMLRenderer):
    pass


def create(
    escape: bool = True, header_level_delta: None | int = None
) -> Callable[[str], str]:

    r = mistune.create_markdown(
        plugins=[
            "strikethrough",
            "table",
            "footnotes",
            "url",
            mistune.directives.FencedDirective(
                [mistune.directives.Figure(), mistune.directives.TableOfContents()]
            ),
        ],
        renderer=(
            CustomHTMLRenderer(header_level_delta, escape=escape)
            if header_level_delta is not None
            else mistune.HTMLRenderer(escape=escape)
        ),
    )

    def shim(*args, **kwargs):
        return '<div class="rendered-markdown">' + r(*args, **kwargs) + "</div>"

    return shim
