import time

from fabric.api import settings, sudo
from fabric.contrib import files

from fabulaws.decorators import uses_fabric
from fabulaws.ubuntu.packages.base import AptMixin


class RabbitMqMixin(AptMixin):
    """
    FabulAWS Ubuntu mixin that configures RabbitMQ
    """

    package_name = "rabbitmq"
    rabbitmq_packages = ["rabbitmq-server"]
    rabbitmq_ulimit = 20000

    @uses_fabric
    def rabbitmq_service(self, cmd):
        return sudo("service rabbitmq-server {0}".format(cmd))

    def bind_app_directories(self, *args, **kwargs):
        tries = kwargs.pop("rabbitmq_tries", 10)
        sleep = kwargs.pop("rabbitmq_sleep", 2)
        # make sure we stop before proceeding in case we get moved to a secure directory
        self.rabbitmq_service("stop")
        super(RabbitMqMixin, self).bind_app_directories(*args, **kwargs)
        # try starting a number of times with warn_only=True, as rabbitmq
        # fails to restart occassionally for unknown reasons
        restarted = False
        for i in range(tries - 1):
            with settings(warn_only=True):
                result = self.rabbitmq_service("start")
                if result.return_code == 0:
                    restarted = True
                    break
                else:
                    time.sleep(sleep)
        # if we haven't succeeded yet, start again without warn_only=True
        # and let the failure be handled as usual by Fabric
        if not restarted:
            self.rabbitmq_service("start")

    @uses_fabric
    def rabbitmq_command(self, command):
        """Run a rabbitmqctl command."""

        sudo("rabbitmqctl %s" % command)

    def create_mq_user(self, username, password):
        """Create a rabbitmq user."""

        self.rabbitmq_command("add_user %s %s" % (username, password))

    def create_mq_vhost(self, name):
        """Create a rabbitmq vhost."""

        self.rabbitmq_command("add_vhost %s" % name)

    def set_mq_vhost_permissions(self, vhost, username, permissions='".*" ".*" ".*"'):
        """Set permssions for a user on a given vhost."""

        self.rabbitmq_command(
            "set_permissions -p %s %s %s" % (vhost, username, permissions)
        )

    @uses_fabric
    def rabbitmq_configure(self):
        files.append(
            "/etc/default/rabbitmq-server",
            "ulimit -n %s" % self.rabbitmq_ulimit,
            use_sudo=True,
        )
        self.rabbitmq_service("restart")

    def setup(self):
        """Redis mixin"""

        super(RabbitMqMixin, self).setup()
        self.rabbitmq_configure()


class RabbitMqOfficialMixin(RabbitMqMixin):
    """
    Installs RabbitMQ from the official upstream APT repository.
    """

    rabbitmq_aptrepo = (
        "http://www.rabbitmq.com/debian/",
        "testing",
        "main",
        "056E8E56",
    )
    rabbitmq_packages = ["rabbitmq-server"]
