# -*- coding: utf-8 -*-
import inspect
import os
import re


from django.apps import apps
from django.core.management import color
from django.core.management import BaseCommand
from django.utils import termcolors
from django.utils.encoding import smart_str

from django_extensions.compat import load_tag_library
from django_extensions.management.color import _dummy_style_func
from django_extensions.management.utils import signalcommand


def no_style():
    style = color.no_style()
    for role in ('FILTER', 'MODULE_NAME', 'TAG', 'TAGLIB'):
        setattr(style, role, _dummy_style_func)
    return style


def color_style():
    style = color.color_style()
    style.FILTER = termcolors.make_style(fg='yellow', opts=('bold',))
    style.MODULE_NAME = termcolors.make_style(fg='green', opts=('bold',))
    style.TAG = termcolors.make_style(fg='red', opts=('bold',))
    style.TAGLIB = termcolors.make_style(fg='blue', opts=('bold',))
    return style


def format_block(block, nlspaces=0):
    """
    Format the given block of text, trimming leading/trailing
    empty lines and any leading whitespace that is common to all lines.
    The purpose is to let us list a code block as a multiline,
    triple-quoted Python string, taking care of
    indentation concerns.
    https://code.activestate.com/recipes/145672/
    """
    # separate block into lines
    lines = smart_str(block).split('\n')

    # remove leading/trailing empty lines
    while lines and not lines[0]:
        del lines[0]
    while lines and not lines[-1]:
        del lines[-1]

    # look at first line to see how much indentation to trim
    ws = re.match(r'\s*', lines[0]).group(0)
    if ws:
        lines = map(lambda x: x.replace(ws, '', 1), lines)

    # remove leading/trailing blank lines (after leading ws removal)
    # we do this again in case there were pure-whitespace lines
    while lines and not lines[0]:
        del lines[0]
    while lines and not lines[-1]:
        del lines[-1]

    # account for user-specified leading spaces
    flines = ['%s%s' % (' ' * nlspaces, line) for line in lines]

    return '\n'.join(flines) + '\n'


class Command(BaseCommand):
    help = "Displays template tags and filters available in the current project."
    results = ""

    def add_result(self, s, depth=0):
        self.results += '%s\n' % s.rjust(depth * 4 + len(s))

    @signalcommand
    def handle(self, *args, **options):
        if options['no_color']:
            style = no_style()
        else:
            style = color_style()

        for app_config in apps.get_app_configs():
            app = app_config.name
            try:
                templatetag_mod = __import__(app + '.templatetags', {}, {}, [''])
            except ImportError:
                continue
            mod_path = inspect.getabsfile(templatetag_mod)
            mod_files = os.listdir(os.path.dirname(mod_path))
            tag_files = [i.rstrip('.py') for i in mod_files if i.endswith('.py') and i[0] != '_']
            app_labeled = False
            for taglib in tag_files:
                lib = load_tag_library(taglib)
                if lib is None:
                    continue

                if not app_labeled:
                    self.add_result('App: %s' % style.MODULE_NAME(app))
                    app_labeled = True
                self.add_result('load: %s' % style.TAGLIB(taglib), 1)
                libstuff = [
                    (lib.tags, 'Tag:', style.TAG),
                    (lib.filters, 'Filter:', style.FILTER)
                ]
                for items, label, style_func in libstuff:
                    for item in items:
                        self.add_result('%s %s' % (label, style_func(item)), 2)
                        doc = inspect.getdoc(items[item])
                        if doc:
                            self.add_result(format_block(doc, 12))
        return self.results
