import tornado.template

from pypugjs import Compiler as _Compiler
from pypugjs.exceptions import CurrentlyNotSupported
from pypugjs.runtime import attrs, escape, iteration
from pypugjs.utils import process

ATTRS_FUNC = '__pypugjs_attrs'
ESCAPE_FUNC = '__pypugjs_escape'
ITER_FUNC = '__pypugjs_iter'


class Compiler(_Compiler):
    def visitCodeBlock(self, block):
        self.buffer('{%% block %s %%}' % block.name)
        if block.mode == 'append':
            self.buffer('{% raw super() %}')
        self.visitBlock(block)
        if block.mode == 'prepend':
            self.buffer('{% raw super() %}')
        self.buffer('{% end %}')

    def interpolate(self, text, escape=True):
        return self._interpolate(
            text, lambda x: '{%% raw %s(%s) %%}' % (ESCAPE_FUNC, x)
        )

    def visitMixin(self, mixin):
        raise CurrentlyNotSupported('mixin')

    def visitAssignment(self, assignment):
        self.buffer('{%% set %s = %s %%}' % (assignment.name, assignment.val))

    def visitCode(self, code):
        if code.buffer:
            val = code.val.lstrip()
            val = self.var_processor(val)
            if code.escape:
                self.buf.append('{%% raw %s(%s) %%}' % (ESCAPE_FUNC, val))
            else:
                self.buf.append('{%% raw %s %%}' % val)
        else:
            self.buf.append('{%% %s %%}' % code.val)

        if code.block:
            # if not code.buffer: self.buf.append('{')
            self.visit(code.block)
            # if not code.buffer: self.buf.append('}')

            if not code.buffer:
                codeTag = code.val.strip().split(' ', 1)[0]
                if codeTag in self.auto_close_code:
                    self.buf.append('{%% end%s %%}' % codeTag)

    def visitEach(self, each):
        self.buf.append(
            '{%% for %s in %s(%s,%s) %%}'
            % (','.join(each.keys), ITER_FUNC, each.obj, len(each.keys))
        )
        self.visit(each.block)
        self.buf.append('{% end %}')

    def visitConditional(self, conditional):
        TYPE_CODE = {
            'if': lambda x: 'if %s' % x,
            'unless': lambda x: 'if not %s' % x,
            'elif': lambda x: 'elif %s' % x,
            'else': lambda x: 'else',
        }
        self.buf.append(
            '{%% %s %%}' % TYPE_CODE[conditional.type](conditional.sentence)
        )
        if conditional.block:
            self.visit(conditional.block)
            for next in conditional.next:
                self.visitConditional(next)
        if conditional.type in ['if', 'unless']:
            self.buf.append('{% end %}')

    def attributes(self, attrs):
        return "{%% raw %s(%s) %%}" % (ATTRS_FUNC, attrs)


class Template(tornado.template.Template):
    def __init__(self, template_string, name="<string>", *args, **kwargs):
        is_pugjs = name.endswith(".pug")
        if is_pugjs:
            template_string = process(template_string, filename=name, compiler=Compiler)

        super(Template, self).__init__(template_string, name, *args, **kwargs)
        if is_pugjs:
            self.namespace.update(
                {ATTRS_FUNC: attrs, ESCAPE_FUNC: escape, ITER_FUNC: iteration}
            )


# Patch tornado template engine for preprocess PugJS templates
def patch_tornado():
    tornado.template.Template = Template
