# -*- coding: utf-8 -*-
"""Tweaked Mistune
"""

import os
import re
from .Cache import cache_img
import mistune
from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import html


class DPlayerLexer(object):
    """Before Autotag

    [dplayer]url[/dplayer] => <div class="dplayer" data-url="url"></div>
    """

    def enable_dplayer(self):
        self.rules.dplayer = re.compile(
            r' *?\[.*?dplayer([\s\S]*?)\]'
            r'([\s\S]*?)'
            r'\[/.*?dplayer.*?\]'
        )
        self.default_rules.insert(4, 'dplayer')

    def parse_dplayer(self, m):
        self.tokens.append({
            'type': 'dplayer',
            'attr': m.group(1),
            'url': m.group(2)
        })


class AutotagLexer(object):
    """Block level aututag

    [tag][/tag] ==> <div class="tag"></div>
    """

    def enable_autotag(self):
        self.rules.autotag = re.compile(
            r' *?\[(.*?)\]'
            r'([\s\S]*?)'
            r'\[/\1\]'
        )
        self.default_rules.insert(4, 'autotag')

    def parse_autotag(self, m):
        self.tokens.append({
            'type': 'autotag',
            'tagname': m.group(1),
            'text': m.group(2)
        })


class RubyLexer(object):
    def enable_ruby(self):
        self.rules.text = re.compile(
            r'^[\s\S]+?(?=[\\<!\[_*`~]|https?://| {2,}\n|\{\{|$)')
        self.rules.ruby = re.compile(
            r'\{\{'                   # {{
            r'([\s\S]*?:[\s\S]*?)'   # text|ruby
            r'\}\}'             # }}
        )
        self.default_rules.insert(0, 'ruby')

    def output_ruby(self, m):
        text = m.group(1)
        text, ruby = text.split(':')
        return self.renderer.ruby(text, ruby)


class LinkcardLexer(object):
    def enable_linkcard(self):
        self.rules.linkcard = re.compile(
            r'.*?\[([\s\S]+?)\]\(([\s\S]+?)\)\+\(([\s\S]+?)\)')
        self.default_rules.insert(0, 'linkcard')

    def output_linkcard(self, m):
        return self.renderer.linkcard(m.group(1), m.group(2), m.group(3))


class InlineFootnoteLexer(object):
    inline_footnotes = []

    def enable_inline_footnote(self):
        self.inline_footnotes = []
        self.rules.inline_footnote = re.compile(r'\[\^([\s\S]*?)\]')
        self.default_rules.insert(0, 'inline_footnote')

    def output_inline_footnote(self, m):
        self.inline_footnotes.append(m.group(1))
        id = str(len(self.inline_footnotes))
        return self.renderer.inline_footnote(id)


class MathBlockMixin(object):
    """Math mixin for BlockLexer, mix this with BlockLexer::

        class MathBlockLexer(MathBlockMixin, BlockLexer):
            def __init__(self, *args, **kwargs):
                super(MathBlockLexer, self).__init__(*args, **kwargs)
                self.enable_math()
    """

    def enable_math(self):
        self.rules.block_math = re.compile(r'^\$\$(.*?)\$\$', re.DOTALL)
        self.rules.block_latex = re.compile(
            r'^\\begin\{([a-z]*\*?)\}(.*?)\\end\{\1\}', re.DOTALL
        )
        self.default_rules.extend(['block_math', 'block_latex'])

    def parse_block_math(self, m):
        """Parse a $$math$$ block"""
        self.tokens.append({
            'type': 'block_math',
            'text': m.group(1)
        })

    def parse_block_latex(self, m):
        self.tokens.append({
            'type': 'block_latex',
            'name': m.group(1),
            'text': m.group(2)
        })


class MathInlineMixin(object):
    """Math mixin for InlineLexer, mix this with InlineLexer::

        class MathInlineLexer(InlineLexer, MathInlineMixin):
            def __init__(self, *args, **kwargs):
                super(MathInlineLexer, self).__init__(*args, **kwargs)
                self.enable_math()
    """

    def enable_math(self):
        self.rules.math = re.compile(r'^\$(.+?)\$')
        self.default_rules.insert(0, 'math')
        self.rules.text = re.compile(
            r'^[\s\S]+?(?=[\\<!\[_*`~\$]|https?://| {2,}\n|\{\{|$)')

    def output_math(self, m):
        return self.renderer.math(m.group(1))


class MathRendererMixin(object):
    def block_math(self, text):
        return '$$%s$$' % text

    def block_latex(self, name, text):
        return r'\begin{%s}%s\end{%s}' % (name, text, name)

    def math(self, text):
        return '$%s$' % text


class MyMarkdown(mistune.Markdown):
    def output_autotag(self):
        return self.renderer.autotag(self.token['tagname'],
                                     self.inline(self.token['text']))

    def output_dplayer(self):
        return self.renderer.dplayer(self.token['url'], self.token['attr'])

    def __call__(self, text):
        # override this to support inline footnote
        content = self.parse(text)
        if not self.inline.inline_footnotes:
            return content

        addon = ''
        for index in range(len(self.inline.inline_footnotes)):
            footnote = self.inline.inline_footnotes[index]
            footnote = mistune.escape(footnote)
            id = str(index+1)
            addon += '<li id="fn_%s">%s <a no-style href="#fn_ref_%s">↩</a></li>' % (
                id, footnote, id)

        return '%s<hr><div class="footnotes"><ol>%s</ol></div>' % (content, addon)


class MyRenderer(mistune.Renderer, MathRendererMixin):
    def block_code(self, code, lang):
        if not lang:
            return '\n<pre><code>%s</code></pre>\n' % \
                mistune.escape(code)
        lexer = get_lexer_by_name(lang, stripall=True)
        formatter = html.HtmlFormatter()
        return highlight(code, lexer, formatter)

    def image(self, src, title, text):
        figcaption = title or ''
        if figcaption == '' and self.options['parse_alt_as_figcaption']:
            figcaption = text or ''

        ret = cache_img(src, os.path.dirname(self.options['md_path']))
        src = ret['src']
        attr = 'data-width="%s" data-height="%s"' % (
            ret['width'], ret['height'])

        style = ''
        if ret['width'] != -1 and ret['height'] != -1:
            style = 'style="flex: %s"' % str(ret['width'] * 50 / ret['height'])

        if ret['width'] == -1 or ret['height'] == -1:
            attr += " size-undefined"

        if figcaption != "":
            figcaption = '<figcaption>%s</figcaption>' % figcaption

        return '<figure class="pswp-item" %s %s><img src="%s" alt="%s" />%s</figure>' \
            % (style, attr, src, text, figcaption)

    def autotag(self, tagname, text):
        return '<div class="%s">%s</div>' % (tagname, text)

    def dplayer(self, url, attr):
        return '<div class="dplayer" %s data-url="%s"></div>' % (attr, url)

    def ruby(self, text, ruby):
        return '<ruby>%s<rp>(</rp><rt>%s</rt><rp>)</rp></ruby>' % (text, ruby)

    def linkcard(self, name, url, image):
        return '<a style="display:block" target="_blank" href="%s" class="board-item"> \
                <div class="board-thumb"><img src="%s"></div> \
                <div class="board-title">%s</div></a>' % (url, image, name)

    def inline_footnote(self, id):
        return '<sup id="fn_ref_%s"><a href="#fn_%s">%s</a></sup>' % (id, id, id)


class MyBlockLexer(mistune.BlockLexer, AutotagLexer, MathBlockMixin, DPlayerLexer):
    pass


class MyInlineLexer(mistune.InlineLexer, RubyLexer, LinkcardLexer, InlineFootnoteLexer, MathInlineMixin):
    pass


def Markdown(content, parse_alt_as_figcaption=True):
    ren = MyRenderer(escape=False, md_path=content.get_meta("path"),
                     parse_alt_as_figcaption=parse_alt_as_figcaption)

    inline = MyInlineLexer(ren)
    inline.enable_ruby()
    inline.enable_linkcard()
    inline.enable_inline_footnote()
    inline.enable_math()

    block = MyBlockLexer()
    block.enable_autotag()
    block.enable_dplayer()  # should be before autotag
    block.enable_math()

    return MyMarkdown(renderer=ren, block=block, inline=inline)(content.text)
