# Copyright 2016 Oliver Cope
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import unicode_literals

from os.path import basename, dirname, join as pjoin
from tempfile import NamedTemporaryFile, mkdtemp
import contextlib
import io
import os
import re
import shutil

import pytest

from piglet import TemplateLoader


@pytest.fixture
def tmpfile():
    with NamedTemporaryFile() as tmp:
        yield tmp


@contextlib.contextmanager
def tmpdir():
    t = mkdtemp()
    yield t
    shutil.rmtree(t)


@contextlib.contextmanager
def create_templates(paths):
    """
    Write template files to a temporary directory

    :param paths: list of (path, content) tuples
    :returns: path to temporary directory
    """
    if isinstance(paths, dict):
        paths = paths.items()

    with tmpdir() as d:
        paths = [(pjoin(d, *p.split('/')), content) for p, content in paths]
        for p, c in paths:
            try:
                os.makedirs(dirname(p))
            except OSError:
                pass
            with io.open(p, 'w', encoding='UTF-8') as f:
                f.write(c)

        try:
            yield d
        except Exception:
            import traceback
            traceback.print_exc()
            raise


def test_it_loads_a_template(tmpfile):
    template_text = '<h1>whoa nelly!</h1>'
    tmpfile.write(template_text.encode('UTF-8'))
    tmpfile.flush()
    loader = TemplateLoader([dirname(tmpfile.name)])
    assert loader.load(basename(tmpfile.name)).render({}) == template_text


def test_it_caches_files(tmpfile):
    d, filename = os.path.split(tmpfile.name)
    loader = TemplateLoader([d], auto_reload=True)
    with open(tmpfile.name, 'wb') as f:
        f.write(b't1')
    t = loader.load(filename)
    assert loader.load(filename) is t
    with open(tmpfile.name, 'wb') as f:
        f.write(b't2')
    assert loader.load(filename) is not t


def test_it_searches_path():

    template_text = '<h1>whoa nelly!</h1>'

    with tmpdir() as t1, tmpdir() as t2, tmpdir() as t3:
        loader = TemplateLoader([t1, t2, t3])
        for d in [t1, t2, t3]:
            with NamedTemporaryFile(dir=d) as f:
                f.write(template_text.encode('utf-8'))
                f.flush()
                t = loader.load(basename(f.name))
                assert t.render({}) == template_text
                assert t.filename == f.name


def test_it_loads_from_inside_template_same_dir():
    with create_templates([
        ('a/t1', u't1 <py:block name="b">hello</py:block>'),
        ('a/t2', u'<a py:extends="t1"><py:block name="b">t2</py:block></a>')]
    ) as d:
        loader = TemplateLoader([d])
        assert loader.load('a/t2').render({}) == 't1 t2'


def test_it_caches_python_source():
    with create_templates([('t1', u'whoa nelly!')]) as d:
        loader = TemplateLoader([d], cache_dir=d)
        loader.load('t1')
        cache_file = os.path.join(
            d,
            next(f for f in os.listdir(d) if f.endswith('.py'))
        )
        with io.open(cache_file, 'r') as f:
            cached = f.read()
        assert re.compile(r"yield u?'whoa nelly!'").search(cached) is not None

        loader._cache.clear()
        loader._level2_cache.clear()

        with io.open(cache_file, 'w') as f:
            f.write(cached.replace('nelly', 'smelly'))
        assert loader.load('t1').render({}) == 'whoa smelly!'


def test_it_loads_from_across_template_dirs():
    templates = create_templates([
        ('a/t1', u't1 <py:block name="b">hello</py:block>'),
        ('b/t2', u'<a py:extends="t1"><py:block name="b">t2</py:block></a>')])

    with templates as d:
        loader = TemplateLoader([pjoin(d, 'a'), pjoin(d, 'b')])
        assert loader.load('t2').render({}) == 't1 t2'

        TemplateLoader([pjoin(d, 'b'), pjoin(d, 'a')])
        assert loader.load('t2').render({}) == 't1 t2'


def test_it_loads_relative():
    templates = create_templates([
        ('a/t1', 'a-t1 <py:block name="b">hello</py:block>'),
        ('b/t1', 'b-t1 <py:block name="b">hello</py:block>'),
        ('b/t2', '<a py:extends="./t1"><py:block name="b">t2</py:block></a>')])
    with templates as d:
        loader = TemplateLoader([pjoin(d, 'a'), pjoin(d, 'b')])
        assert loader.load('t2').render({}) == 'b-t1 t2'


def test_it_loads_absolute():
    templates = create_templates([
        ('a/t1', 'a-t1 <py:block name="b">hello</py:block>'),
        ('b/t1', 'b-t1 <py:block name="b">hello</py:block>'),
        ('b/t2', '<a py:extends="t1"><py:block name="b">t2</py:block></a>')])
    with templates as d:
        loader = TemplateLoader([pjoin(d, 'a'), pjoin(d, 'b')])
        assert loader.load('t2').render({}) == 'a-t1 t2'


def test_it_doesnt_load_current_template():
    templates = create_templates([
        ('a/page', 'a-page <py:extends href="layout"></py:extends>'),
        ('a/layout', 'a-layout <py:extends href="layout"></py:extends>'),
        ('b/layout', 'b-layout')])
    with templates as d:
        loader = TemplateLoader([pjoin(d, 'a'), pjoin(d, 'b')])
        assert loader.load('page').render({}) == 'a-page a-layout b-layout'
