# coding=utf-8
from __future__ import absolute_import, division, print_function, \
    unicode_literals

import datetime
from textwrap import dedent

import html5lib
import mock
from flask import Flask
from flask_babel import Babel
from jinja2 import Environment
from pytest import fixture
from pytz import timezone, utc

from .. import filters

env = Environment()
filters.init_filters(env)


def en_locale():
    return "en"


def user_tz():
    # This one is GMT+8 and has no DST (tests should pass any time in year)
    return "Asia/Hong_Kong"


USER_TZ = timezone(user_tz())


def test_labelize():
    labelize = filters.labelize
    assert labelize("test_case") == "Test Case"


def test_filesize():
    filesize = filters.filesize
    assert str(filesize("100")) == "100&nbsp;B"
    assert str(filesize(100)) == "100&nbsp;B"
    assert str(filesize(1000)) == "1.0&nbsp;kB"
    assert str(filesize(1100)) == "1.1&nbsp;kB"
    assert str(filesize(10000)) == "10&nbsp;kB"
    assert str(filesize(1100100)) == "1.1&nbsp;MB"
    assert str(filesize(10000000)) == "10&nbsp;MB"
    assert str(filesize(1100100000)) == "1.1&nbsp;GB"
    assert str(filesize(100000000000)) == "100&nbsp;GB"


def test_roughsize():
    roughsize = filters.roughsize
    assert "6" == roughsize(6)
    assert "15" == roughsize(15)
    assert "130+" == roughsize(134)
    assert "10+" == roughsize(15, above=10)
    assert "55+" == roughsize(57, mod=5)


def test_abbrev():
    abbrev = filters.abbrev
    assert "test" == abbrev("test", 20)
    assert "Longer test...e truncated" == abbrev(
        "Longer test. it should be truncated", 25
    )


def test_linkify():
    tmpl = env.from_string('{{ "http://test.example.com"|linkify}}')
    rendered = tmpl.render()
    el = html5lib.parseFragment(rendered)
    assert len(el.getchildren()) == 1

    el = el.getchildren()[0]
    assert el.tag == "{http://www.w3.org/1999/xhtml}a"
    assert el.text == "http://test.example.com"
    assert sorted(el.items()) == [
        ("href", "http://test.example.com"),
        ("rel", "nofollow"),
    ]


def test_nl2br():
    tmpl = env.from_string(
        '{{ "first line\nsecond line\n\n  third, indented" | nl2br }}'
    )
    assert (
        tmpl.render()
        == "first line<br />\nsecond line<br />\n<br />\n  third, indented"
    )


def test_paragraphs():
    markdown_text = dedent(
        """\
        {{ "First paragraph
        some text
        with line return

        Second paragraph
        ... lorem

        Last one - a single line" | paragraphs }}
        """
    )
    tmpl = env.from_string(markdown_text)

    expected = dedent(
        """\
        <p>First paragraph<br />
        some text<br />
        with line return</p>

        <p>Second paragraph<br />
        ... lorem</p>

        <p>Last one - a single line</p>
        """
    )
    assert tmpl.render().strip() == expected.strip()


@fixture
def app():
    app = Flask(__name__)
    babel = Babel(app, default_locale="fr", default_timezone=USER_TZ)
    babel.localeselector(en_locale)
    babel.timezoneselector(user_tz)
    with app.app_context():
        yield app


def test_date_age(app):
    date_age = filters.date_age
    now = datetime.datetime(2012, 6, 10, 10, 10, 10, tzinfo=utc)
    assert date_age(None) == ""

    dt = datetime.datetime(2012, 6, 10, 10, 10, 0, tzinfo=utc)
    assert date_age(dt, now) == "2012-06-10 18:10 (1 minute ago)"

    dt = datetime.datetime(2012, 6, 10, 10, 8, 10, tzinfo=utc)
    assert date_age(dt, now) == "2012-06-10 18:08 (2 minutes ago)"

    dt = datetime.datetime(2012, 6, 10, 8, 30, 10, tzinfo=utc)
    assert date_age(dt, now) == "2012-06-10 16:30 (2 hours ago)"

    # for coverage: test when using default parameter now=None
    dt_patcher = mock.patch.object(
        filters.datetime, "datetime", mock.Mock(wraps=datetime.datetime)
    )
    with dt_patcher as mocked:
        mocked.utcnow.return_value = now
        assert date_age(dt) == "2012-06-10 16:30 (2 hours ago)"


def test_age(app):
    age = filters.age
    now = datetime.datetime(2012, 6, 10, 10, 10, 10, tzinfo=utc)
    d1m = datetime.datetime(2012, 6, 10, 10, 10, 0, tzinfo=utc)
    d3w = datetime.datetime(2012, 5, 18, 8, 0, 0, tzinfo=utc)
    d2011 = datetime.datetime(2011, 9, 4, 12, 12, 0, tzinfo=utc)

    # default parameters
    assert age(None) == ""
    assert age(d1m, now) == "1 minute ago"
    assert age(d3w, now) == "3 weeks ago"

    # with direction
    assert age(d1m, now, add_direction=False) == "1 minute"
    assert age(d3w, now, add_direction=False) == "3 weeks"

    # with date_threshold
    assert age(d1m, now, date_threshold="day") == "1 minute ago"
    # same year: 2012 not shown
    assert age(d3w, now, date_threshold="day") == "May 18, 4:00 PM"
    # different year: 2011 shown
    assert age(d2011, now, date_threshold="day") == "September 4, 2011, 8:12 PM"

    # using default parameter now=None
    dt_patcher = mock.patch.object(
        filters.datetime, "datetime", mock.Mock(wraps=datetime.datetime)
    )
    with dt_patcher as mocked:
        mocked.utcnow.return_value = now
        assert age(d1m) == "1 minute ago"
