# vi: syntax=python
import os
import fabric

from fabric.api import run, sudo, cd

fabric.state.env.colorize_errors = True
fabric.state.output['stdout'] = False

# task const variables
VARS = dict(
    current_user=fabric.state.env.user,

    # project settings
    project_name='{{ proj_name }}',
    user_data=dict(
        username='root',
        email='root@e.co',
        password='123123'
    ),

    # dirs configs
    templates_dir='./provision/templates',
    root_dir='/home/vagrant/proj',
    venv_path='/home/vagrant/venv',
    base_dir='/home/vagrant',

    # nginx config
    http_host='{{ proj_ip }}',
    http_port='80',
{% if POSTGRES %}
    # database config
    db_name='{{ proj_name }}',
    db_password='{{ db_pass }}',
    db_user='{{ db_user }}',
{% endif %}
    # locale conf
    locale='ru_RU',
    encoding='UTF-8',
)


def sentinel(sentinel_name):
    def sentinel_wrapp(function):
        def wrapped():
            sentinel_path = '/usr/sentinel_{}'.format(sentinel_name)
            if fabric.contrib.files.exists(sentinel_path):
                fabric.utils.warn('skip {}'.format(sentinel_name))
                return
            function()
            sudo('touch {}'.format(sentinel_path))
        return wrapped
    return sentinel_wrapp


def common():
    """ Common tasks """
    locale()
    apt_packages()
    python_packages()


def nginx():
    """ Install nginx tasks """
    # install nginx
    sudo('apt-get -y install nginx')
    # create nginx config file for project
    fabric.contrib.files.upload_template(
        'nginx-host.j2', '/etc/nginx/sites-available/{project_name}'.format(**VARS),
        context=VARS, use_jinja=True, backup=False, use_sudo=True, template_dir=VARS['templates_dir'])
    # make s-link to enabled sites
    sudo('ln -sf /etc/nginx/sites-available/{project_name} /etc/nginx/sites-enabled/{project_name}'.format(**VARS))
    # restart nginx
    sudo('service nginx restart')


@sentinel('database')
def database():
    """ Install database """{% if POSTGRES %}
    # install postgres apt
    sudo('apt-get -y install postgresql postgresql-server-dev-all python-psycopg2')
    # make postgers password
    with fabric.context_managers.settings(warn_only=True):
        commands = (
            'CREATE USER {db_user};',
            'ALTER USER {db_user} WITH PASSWORD \'{db_password}\';',
            'ALTER USER {db_user} CREATEDB;',
            'CREATE DATABASE {db_name};',
            'GRANT ALL PRIVILEGES ON DATABASE {db_name} TO {db_user};',
        )
        for command in commands:
            run('sudo -u postgres psql -c "%s"' % command.format(**VARS))
    {% else %}
    pass{% endif %}


@sentinel('locale')
def locale():
    """ Set locale to enviroment """
    fabric.contrib.files.upload_template(
        'environment.j2', '/etc/environment',
        context=VARS, use_jinja=True, backup=False, use_sudo=True, template_dir=VARS['templates_dir'])
    sudo('localedef {locale}.{encoding} -i {locale} -f{encoding}'.format(**VARS))
    # sudo('locale-gen')


@sentinel('apt_packages')
def apt_packages():
    """ Install common packages """
    sudo('apt-get -y update')
    sudo('apt-get -y install libcurl4-gnutls-dev libexpat1-dev gettext libz-dev libssl-dev git{% if REDIS %} redis-server{% endif %}{% if CELERY and not REDIS %} rabbitmq-server{% endif %}')


@sentinel('python')
def python_packages():
    """ Install python components """

    sudo(
        'apt-get -y install python-dev python-pip python-virtualenv build-essential '
        'libncurses5-dev libncursesw5-dev libreadline6-dev libgdbm-dev libsqlite3-dev '
        'libssl-dev libbz2-dev libexpat1-dev liblzma-dev zlib1g-dev libxml2-dev libxslt1-dev')

    with cd('/tmp'):
        # download python source code
        run('wget -O python.tgz https://www.python.org/ftp/python/{{ py_version }}/Python-{{ py_version }}.tgz')
        # extract python tarball
        run('tar -xf python.tgz')
        run('mv Python-{{ py_version }} python')

    with cd('/tmp/python'):
        # configuring python 3.4 Makefile
        run('./configure --prefix=/usr/local/python-{{ py_version }}')
        # compiling the python 3.4 source code and install
        sudo('make && make altinstall #')
    sudo('rm /tmp/* -rf')
    # make link to python
    sudo('ln -sf /usr/local/python-{{ py_version }}/bin/* /usr/local/bin/')


def app():
    """ Run application tasks """
    with cd(VARS['root_dir']):
        # Create venv and install requirements
        run('pyvenv-{{ pyenv_version }} {venv_path}'.format(**VARS))
        {% if init_app %}mk_wheel(){% endif %}
        # Install required python packages with pip from wheels archive
        run('make wheel_install')
        {% if init_app %}start_app(){% endif %}
        # run app tasks for devserver start
        # Copy settings local
        run('cd {project_name} && cp settings_local.py.example settings_local.py'.format(**VARS))


def localserver():
    with cd(VARS['root_dir']):
        # collect static files
        for command in ('migrate --noinput', 'collectstatic --noinput', ):  # 'compilemessages', ):
            run('{venv_path}/bin/python manage.py {command}'.format(command=command, **VARS))
        # make root dir available to read
        # sudo('chmod 755 {base_dir}/static -R'.format(**VARS))
        # Create user
        create_user_py = (
            'from django.contrib.auth import get_user_model'   '\n'
            'User = get_user_model()' '\n'
            'User.objects.create_superuser(**{user_data})'  '\n'
        ).format(**VARS)

        run('echo "{create_user_py}" | {venv_path}/bin/python manage.py shell'.format(
            create_user_py=create_user_py, **VARS))
        run('mkdir var -p')

        # Start{% if CELERY %} celery and{% endif %} runserver
        run('make start', pty=False){% if CELERY %}
        run('make runcelery_multi', pty=False){% endif %}
{% if init_app %}

@sentinel('mk_wheel')
def mk_wheel():
    """ make wheels """
    run('{venv_path}/bin/pip install -U pip wheel'.format(**VARS))
    run('mkdir -p wheels')
    run('{venv_path}/bin/pip wheel -w wheels/ -r requirements-remote.txt --pre --allow-all-external'.format(**VARS))


@sentinel('start_app')
def start_app():
    """ start dj app """
    with fabric.context_managers.settings(warn_only=True):
        run('{venv_path}/bin/django-admin startproject {project_name} .'.format(**VARS))

    with open('{project_name}/settings.py'.format(**VARS), 'r') as settings_file:
        settings = settings_file.read()

    # make replacements
    settings = settings.replace('''
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
''', '''
BASE_DIR = os.path.dirname(os.path.dirname(__file__))

if __name__ in ['settings', '{project_name}.settings']:
    import sys
    sys.path.insert(0, os.path.join(BASE_DIR, '{project_name}'))
'''.format(**VARS))
{% if POSTGRES %}
    settings = settings.replace('''
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
''', '''
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': '%(db_name)s',
        'USER': '%(db_user)s',
        'PASSWORD': '%(db_password)s',
        'HOST': '127.0.0.1',
    }
}''' % VARS)
{% endif %}
    if 'STATIC_ROOT' not in settings:
        settings = settings.replace('''
STATIC_URL = '/static/'
''', '''
TEST_RUNNER = 'rainbowtests.test.runner.RainbowDiscoverRunner'

STATIC_URL = '/static/'
STATIC_ROOT = '%(project_name)s/static'
{% if CELERY %}

# celery settings
broker_connection_link = {% if REDIS %}'redis://localhost:6379/0'{% else %}'amqp://guest:guest@localhost:5672//'{% endif %}

BROKER_URL = CELERY_RESULT_BACKEND = broker_connection_link
CELERY_ACCEPT_CONTENT = ['json', ]
{% endif %}

try:
    from settings_local import *  # noqa
except ImportError:
    pass
''' % VARS)

    with open('{project_name}/settings.py'.format(**VARS), 'w') as settings_file:
        settings_file.write(settings)
{% endif %}
{% if CELERY %}
    with open('{project_name}/__init__.py'.format(**VARS), 'w') as init_file:
        init_file.write('''# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app  # noqa
''')
{% endif %}
{# keep trailing newline #}
