# Copyright (C) 2018-2024 H. Turgut Uyar <uyar@tekir.org>
#
# lektor-chameleon is released under the BSD license.
# Read the included LICENSE.txt file for details.

__version__ = "0.8"

from functools import partial

from chameleon import PageTemplateLoader
from chameleon.loader import TemplateLoader
from lektor.context import get_ctx
from lektor.pluginsystem import Plugin
from lektor.reporter import reporter
from markupsafe import Markup


_CONTEXT_FILTERS = {
    "url", "asseturl", "markdown",
}

_STR_FILTERS = {
    "capitalize", "center", "indent", "length", "lower", "replace", "title",
    "trim", "truncate", "upper", "wordcount", "wordwrap",
}

_JINJA_ENV_FILTERS = {
    "attr", "replace", "truncate", "wordwrap",
}


class Filter:
    def __init__(self, name, func):
        self.name = name
        self.func = func
        self.ctx = self.name in _CONTEXT_FILTERS
        self.str = self.name in _STR_FILTERS

    def __call__(self, *args, **kwargs):
        return Filter(self.name, partial(self.func, *args, **kwargs))

    def __rrshift__(self, x):
        markup = self.str and hasattr(x, "html")
        p = x.html if markup else x
        t = self.func(p)
        y = t.unescape() if hasattr(t, "unescape") else t
        return Markup(y) if markup else y


chameleon_load = TemplateLoader.load


def load_template(self, filename, *args, **kwargs):
    ctx = get_ctx()
    if filename == ctx.source.datamodel.id + ".html":
        filename = ctx.source.datamodel.id + ".pt"
    template = chameleon_load(self, filename, *args, **kwargs)
    ctx.record_dependency(template.filename)
    return template


def render_template(self, name, pad=None, this=None, values=None, alt=None):
    if isinstance(name, list):
        name = name[0]
    ctx = self.make_default_tmpl_values(pad, this, values, alt, template=name)
    ctx.update(self.chameleon_env.globals)
    for f_name, f_filter in self.chameleon_env.filters.items():
        ctx[f_name] = f_filter(ctx) if f_filter.ctx else f_filter
    template = self.chameleon_env.loader.load(name)
    return template(**ctx)


class ChameleonEnvironment:
    def __init__(self, jinja_env) -> None:
        self.loader = PageTemplateLoader(jinja_env.loader.searchpath,
                                         auto_reload=True)
        self.globals = jinja_env.globals
        self.filters = {n: Filter(n, f) for n, f in jinja_env.filters.items()}
        for f_name in _JINJA_ENV_FILTERS:
            self.filters[f_name] = self.filters[f_name](jinja_env)


class ChameleonPlugin(Plugin):
    name = "chameleon"
    description = "Chameleon support for templating"

    def on_setup_env(self, **extra):
        reporter.report_generic("Setting up to use Chameleon templates")
        TemplateLoader.load = load_template
        self.env.__class__.render_template = render_template
        self.env.chameleon_env = ChameleonEnvironment(self.env.jinja_env)
