"""Fabfile for tasks that only manipulate things on the local machine."""
import re

from django.conf import settings

from fabric.api import lcd, local
from fabric.api import settings as fab_settings
from fabric.colors import green, red
from fabric.utils import abort


USER_AND_HOST = '-U {0} -h localhost'.format(settings.LOCAL_PG_ADMIN_ROLE)


def check():
    """Runs flake8, check_coverage and test."""
    flake8()
    test()
    check_coverage()


def check_coverage():
    """Checks if the coverage is 100%."""
    with lcd(settings.LOCAL_COVERAGE_PATH):
        total_line = local('grep -n Total index.html', capture=True)
        match = re.search(r'^(\d+):', total_line)
        total_line_number = int(match.groups()[0])
        percentage_line_number = total_line_number + 4
        percentage_line = local(
            'awk NR=={0} index.html'.format(percentage_line_number),
            capture=True)
        match = re.search(r'<td>(\d.+)%</td>', percentage_line)
        percentage = float(match.groups()[0])
    if percentage < 100:
        abort(red('Coverage is {0}%'.format(percentage)))
    print(green('Coverage is {0}%'.format(percentage)))


def create_db(with_postgis=False):
    """
    Creates the local database.

    :param with_postgis: If ``True``, the postgis extension will be installed.

    """
    local('psql {0} -c "CREATE USER {1} WITH PASSWORD \'{1}\'"'.format(
        USER_AND_HOST, settings.DB_ROLE))
    local('psql {0} -c "CREATE DATABASE {1}"'.format(
        USER_AND_HOST, settings.DB_NAME))
    if with_postgis:
        local('psql {0} {1} -c "CREATE EXTENSION postgis"'.format(
            USER_AND_HOST, settings.DB_NAME))
    local('psql {0} -c "GRANT ALL PRIVILEGES ON DATABASE {1}'
          ' to {1}"'.format(USER_AND_HOST, settings.DB_ROLE))
    local('psql {0} {1} -c "GRANT ALL PRIVILEGES ON ALL TABLES'
          ' IN SCHEMA public TO {2}"'.format(
              USER_AND_HOST, settings.DB_NAME, settings.DB_ROLE))


def delete_db():
    """
    Deletes all data in the database.

    You need django-extensions in order to use this.
    However, please note that this is not as thorough as a real database drop.

    """
    local(' ./manage.py reset_db --router=default --noinput')


def export_db(filename=None):
    """
    Exports the database.

    Make sure that you have this in your ``~/.pgpass`` file:

    localhost:5433:*:<db_role>:<password>

    Also make sure that the file has ``chmod 0600 .pgpass``.

    Usage::

        fab export_db
        fab export_db:filename=foobar.dump

    """
    if not filename:
        filename = settings.DB_DUMP_FILENAME
    local('pg_dump -c -Fc -O -U {0} -f {1}'.format(
        settings.DB_ROLE, filename))


def drop_db():
    """Drops the local database."""
    with fab_settings(warn_only=True):
        local('psql {0} -c "DROP DATABASE {1}"'.format(
            USER_AND_HOST, settings.DB_NAME))


def flake8():
    """Runs flake8 against the codebase."""
    return local('flake8 --ignore=E126 --statistics .')


def import_db(filename=None):
    """
    Imports the database.

    Make sure that you have this in your ``~/.pgpass`` file:

    localhost:5433:*:publishizer_publishizer:publishizer

    Also make sure that the file has ``chmod 0600 .pgpass``.

    Usage::

        fab import_db
        fab import_db:filename=foobar.dump

    """
    if not filename:
        filename = settings.DB_DUMP_FILENAME
    with fab_settings(warn_only=True):
        local('pg_restore -O -c -U {0} -d {1} {2}'.format(
            settings.DB_ROLE, settings.DB_NAME, filename))


def lessc():
    """
    Compiles all less files.

    This is useful if you are using the Twitter Bootstrap Framework.

    TODO: Write a blog post about this.

    """
    local('lessc {0}/static/css/bootstrap.less'
          ' {0}/static/css/bootstrap.css'.format(settings.PROJECT_NAME))
    local('lessc {0}/static/css/responsive.less'
          ' {0}/static/css/bootstrap-responsive.css'.format(
              settings.PROJECT_NAME))


def rebuild():
    """
    Deletes and re-creates your DB. Needs django-extensions and South.

    """
    drop_db()
    create_db()
    local('python2.7 manage.py syncdb --all --noinput')
    local('python2.7 manage.py migrate --fake')


def test(options=None, integration=1,
         test_settings=None):
    """
    Runs manage.py tests.

    Usage::

        fab test
        fab test:app
        fab test:app.tests.forms_tests:TestCaseName
        fab test:integration=0

    """
    if test_settings is None:
        test_settings = settings.TEST_SETTINGS_PATH
    command = ("./manage.py test -v 2 --traceback --failfast" +
               " --settings={0}".format(test_settings))
    if int(integration) == 0:
        command += " --exclude='integration_tests'"
    if options:
        command += ' {0}'.format(options)
    with fab_settings(warn_only=True):
        result = local(command, capture=False)
    if result.failed:
        abort(red('Some tests failed'))
    else:
        print green('All tests passed')
