"""
This module defines Celery_ tasks to manage website configurations.

"""
import os
import subprocess
from tempfile import mkstemp

from jinja2 import Environment, PackageLoader

from celery import shared_task
from celery.utils.log import get_task_logger

from gvaweb import settings


_LOGGER = get_task_logger(__name__)

SUDO_CMD = '/usr/bin/sudo'
RM_CMD = '/bin/rm'
LN_CMD = '/bin/ln'
SERVICE_CMD = '/bin/systemctl'
INSTALL_CMD = '/usr/bin/install'

JINJAENV = Environment(loader=PackageLoader('gvaweb.webtasks', 'templates'))


def _jinja_parentdomain(domain):
    return '.'.join(domain.split('.')[1:])


JINJAENV.filters['parentdomain'] = _jinja_parentdomain


def log_and_raise(exception, message, *args):
    logargs = list(args) + [exception.returncode, exception.output]
    _LOGGER.error(message + "\nreturncode: %d\noutput:\n%s", *logargs)
    raise Exception(message % args)


def log_without_raise(exception, message, *args):
    logargs = list(args) + [exception.returncode, exception.output]
    _LOGGER.error(message + "\nreturncode: %d\noutput:\n%s", *logargs)


def _build_vhost_config_path(sitename):
    return os.path.join(settings.GVAWEB_NGINX_SITES_AVAILABLE, sitename)


def _build_enabled_vhost_path(sitename):
    return os.path.join(settings.GVAWEB_NGINX_SITES_ENABLED, sitename)


def _build_php_fpm_pool_file(username):
    return os.path.join(settings.GVAWEB_PHPFPM_POOL, "{username}.conf".format(
        username=username))


def _build_document_root_path(sitename, username):
    return os.path.join(
        settings.GVAWEB_WWWUSER_MOUNT, username, sitename, 'html')


def _get_template(templatename):
    return JINJAENV.get_template(templatename)


@shared_task
def create_web_vhost_config(username, sitename, wildcard):
    """
    This task creates a virtual host configuration on an nginx web
    server.

    :param str username: user who owns the site
    :param str sitename: site name
    :param boolean wildcard: designates whether this is website has a wildcard
        subdomain
    :return: :py:const:`True` if the creation finished successfully
    :rtype: boolean

    """
    conftmpl = _get_template('vhost.nginx')
    confdata = conftmpl.render(domain=sitename, wildcard=wildcard)
    conffile = None
    try:
        nginxtemp, filename = mkstemp()
        conffile = os.fdopen(nginxtemp, 'w')
        conffile.write(confdata.encode('utf8'))
    finally:
        if conffile:
            conffile.close()
    try:
        subprocess.check_output([
            SUDO_CMD, INSTALL_CMD, '-o', 'root', '-g', 'root', '-m', '0640',
            filename, _build_vhost_config_path(sitename)],
            stderr=subprocess.STDOUT)
        subprocess.check_output([
            SUDO_CMD, RM_CMD, filename], stderr=subprocess.STDOUT)
    except subprocess.CalledProcessError as cpe:
        log_and_raise(
            cpe, 'could not setup site configuration for %s', sitename)
    return True


@shared_task
def disable_web_vhost(sitename):
    """
    This task disables a virtual host configuration on an nginx web server.

    :param str sitename: site name
    :return: :py:const:`True` if the virtual host has been disabled
    :rtype: boolean

    """
    try:
        subprocess.check_output([
            SUDO_CMD, RM_CMD, "-f", _build_enabled_vhost_path(sitename)],
            stderr=subprocess.STDOUT)
        subprocess.check_output([
            SUDO_CMD, SERVICE_CMD, 'reload', 'nginx'],
            stderr=subprocess.STDOUT)
    except subprocess.CalledProcessError as cpe:
        log_and_raise(
            cpe, 'could not disable site configuration for %s', sitename)
    return True


@shared_task
def enable_web_vhost(sitename):
    """
    This task enables an existing virtual host configuration on an nginx web
    server.

    :param str sitename: site name
    :return: :py:const:`True` if the virtual host has been enabled
    :rtype: boolean

    """
    try:
        subprocess.check_output([
            SUDO_CMD, LN_CMD, '-s', '-f',
            _build_vhost_config_path(sitename),
            _build_enabled_vhost_path(sitename)],
            stderr=subprocess.STDOUT)
        subprocess.check_output([
            SUDO_CMD, SERVICE_CMD, 'restart', 'nginx'],
            stderr=subprocess.STDOUT)
    except subprocess.CalledProcessError as cpe:
        log_and_raise(
            cpe, 'could not enable site configuration for %s', sitename)
    return True


@shared_task
def delete_web_vhost_config(sitename):
    """
    This task removes a virtual host configuration on an nginx web server.

    :param str sitename: site name
    :return: :py:const:`True` if the configuration has been deleted
    :rtype: boolean

    """
    try:
        subprocess.check_output([
            SUDO_CMD, RM_CMD, "-f", _build_vhost_config_path(sitename)],
            stderr=subprocess.STDOUT)
    except subprocess.CalledProcessError as cpe:
        log_and_raise(
            cpe, 'could not delete site configuration for %s', sitename)
    return True


@shared_task
def create_web_php_fpm_pool_config(username):
    """
    This task creates a PHP FPM pool configuration.

    :param str username: user name
    :return: :py:const:`True` if the creation finished successfully
    :rtype: boolean

    """
    # TODO: implement PHP FPM docker management
    return True


@shared_task
def delete_web_php_fpm_pool_config(username):
    """
    This task deletes a PHP FPM pool configuration.

    :param str username: user name
    :return: :py:const:`True` if the pool has been deleted
    :rtype: boolean

    """
    try:
        subprocess.check_output([
            SUDO_CMD, RM_CMD, "-f", _build_php_fpm_pool_file(username)],
            stderr=subprocess.STDOUT)
    except subprocess.CalledProcessError as cpe:
        log_without_raise(
            cpe, 'could not delete PHP FPM configuration for %s', username)
    return True