import decimal
import textwrap

from orchestra.contrib.orchestration import ServiceController
from orchestra.contrib.resources import ServiceMonitor

from . import settings


class ProxmoxOVZ(ServiceController):
    model = 'vps.VPS'
    
    RESOURCES = (
        ('memory', 'mem'),
        ('swap', 'swap'),
        ('disk', 'disk')
    )
    GET_PROXMOX_INFO = textwrap.dedent("""
        function get_vz_info () {
            hostname=$1
            version=$(pveversion | cut -d '/' -f2 | cut -d'.' -f1)
            if [[ $version -lt 2 ]]; then
                conf=$(grep "CID\\|:$hostname:" /var/lib/pve-manager/vzlist | grep -B1 ":$hostname:")
                CID=$(echo "$conf" | head -n1 | cut -d':' -f2)
                CTID=$(echo "$conf" | tail -n1 | cut -d':' -f1)
                node=$(pveca -l | grep "^\\s*$CID\\s*:" | awk {'print $3'})
            else
                conf=$(grep -r "HOSTNAME=\\"$hostname\\"" /etc/pve/nodes/*/openvz/*.conf)
                node=$(echo "${conf}" | cut -d"/" -f5)
                CTID=$(echo "${conf}" | cut -d"/" -f7 | cut -d"\\." -f1)
            fi
            echo $CTID $node
        }""")
    
    def prepare(self):
        super(ProxmoxOVZ, self).prepare()
        self.append(self.GET_PROXMOX_INFO)
    
    def get_vzset_args(self, context):
        args = list(settings.VPS_DEFAULT_VZSET_ARGS)
        for resource, arg_name in self.RESOURCES:
            try:
                allocation = context[resource]
            except KeyError:
                pass
            else:
                args.append('--%s %i' % (arg_name, allocation))
        return ' '.join(args)
    
    def run_ssh_commands(self, ssh_commands):
        commands = '\n    '.join(ssh_commands)
        self.append(textwrap.dedent("""\
            cat << EOF | ssh root@${info[1]}
                %s
            EOF""") % commands
        )
    
    def save(self, vps):
        # TODO create the container
        context = self.get_context(vps)
        self.append(textwrap.dedent("""
            info=( $(get_vz_info %(hostname)s) )
            echo "Managing ${info[@]}"\
            """) % context
        )
        ssh_commands = []
        vzset_args = self.get_vzset_args(context)
        if vzset_args:
            context['vzset_args'] = vzset_args
            ssh_commands.append("pvectl vzset ${info[0]} %(vzset_args)s" % context)
        if hasattr(vps, 'password'):
            context['password'] = vps.password.replace('$', '\\$')
            ssh_commands.append(textwrap.dedent("""\
                echo 'root:%(password)s' \\
                    | chroot /var/lib/vz/private/${info[0]} chpasswd -e""") % context
            )
        self.run_ssh_commands(ssh_commands)
    
    def get_context(self, vps):
        context = {
            'hostname': vps.hostname,
        }
        for resource, __ in self.RESOURCES:
            try:
                allocation = getattr(vps.resources, resource).allocated
            except AttributeError:
                pass
            else:
                context[resource] = allocation
        return context


class ProxmoxOpenVZTraffic(ServiceMonitor):
    model = 'vps.VPS'
    resource = ServiceMonitor.TRAFFIC
    monthly_sum_old_values = True
    GET_PROXMOX_INFO = ProxmoxOVZ.GET_PROXMOX_INFO

    def prepare(self):
        super(ProxmoxOpenVZTraffic, self).prepare()
        self.append(self.GET_PROXMOX_INFO)
        self.append(textwrap.dedent("""
            function monitor () {
                object_id=$1
                hostname=$2
                info=( $(get_vz_info $hostname) )
                cat << EOF | ssh root@${info[1]}
                    vzctl exec ${info[0]} cat /proc/net/dev \\
                        | grep venet0 \\
                        | tr ':' ' ' \\
                        | awk '{sum=\\$2+\\$10} END {printf ("$object_id %0.0f\\n", sum)}'
            EOF
            }
            """)
        )
    
    def process(self, line):
        """ diff with last stored state """
        object_id, value, state = super(ProxmoxOpenVZTraffic, self).process(line)
        value = decimal.Decimal(value)
        last = self.get_last_data(object_id)
        if not last or last.state > value:
            return object_id, value, value
        return object_id, value-last.state, value
    
    def monitor(self, vps):
        """ Get OpenVZ container traffic on a Proxmox cluster """
        context = self.get_context(vps)
        self.append('monitor %(object_id)s %(hostname)s' % context)
    
    def get_context(self, vps):
        return {
            'object_id': vps.id,
            'hostname': vps.hostname,
        }