# -*- coding: utf8 -*-
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.
import django.forms
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon import messages

from tuskar_ui import api
import tuskar_ui.forms
from tuskar_ui.utils import utils


DEFAULT_KERNEL_IMAGE_NAME = 'bm-deploy-kernel'
DEFAULT_RAMDISK_IMAGE_NAME = 'bm-deploy-ramdisk'

CPU_ARCH_CHOICES = [
    ('', _("unspecified")),
    ('amd64', _("amd64")),
    ('x86', _("x86")),
    ('x86_64', _("x86_64")),
]
DRIVER_CHOICES = [
    ('pxe_ipmitool', _("IPMI Driver")),
    ('pxe_ssh', _("PXE + SSH")),
]


def get_driver_info_dict(data):
    driver = data['driver']
    driver_dict = {'driver': driver,
                   'deployment_kernel': data['deployment_kernel'],
                   'deployment_ramdisk': data['deployment_ramdisk'],
                   }
    if driver == 'pxe_ipmitool':
        driver_dict.update(
            ipmi_address=data['ipmi_address'],
            ipmi_username=data.get('ipmi_username'),
            ipmi_password=data.get('ipmi_password'),
        )
    elif driver == 'pxe_ssh':
        driver_dict.update(
            ssh_address=data['ssh_address'],
            ssh_username=data['ssh_username'],
            ssh_key_contents=data['ssh_key_contents'],
        )
    return driver_dict


def create_node(request, data):
    cpu_arch = data.get('cpu_arch')
    cpus = data.get('cpus')
    memory_mb = data.get('memory_mb')
    local_gb = data.get('local_gb')

    kwargs = get_driver_info_dict(data)
    kwargs.update(
        cpu_arch=cpu_arch,
        cpus=cpus,
        memory_mb=memory_mb,
        local_gb=local_gb,
        mac_addresses=data['mac_addresses'].split(),
    )
    success = True
    try:
        node = api.node.Node.create(request, **kwargs)
    except Exception:
        success = False
        exceptions.handle(request, _(u"Unable to register node."))
    else:
        # If not all the parameters have been filled in,
        # run the auto-discovery. Note, that the node has been created,
        # so even if we fail here, we report success.
        if not all([cpu_arch, cpus, memory_mb, local_gb]):
            node_uuid = node.uuid
            try:
                api.node.Node.set_maintenance(request, node_uuid, True)
            except Exception:
                exceptions.handle(request, _(
                    u"Can't set maintenance mode on node {0}."
                ).format(node_uuid))
            else:
                try:
                    api.node.Node.discover(request, [node_uuid])
                except Exception:
                    exceptions.handle(request, _(
                        u"Can't start discovery on node {0}."
                    ).format(node_uuid))
    return success


class NodeForm(django.forms.Form):
    id = django.forms.IntegerField(
        label="",
        required=False,
        widget=django.forms.HiddenInput(),
    )

    driver = django.forms.ChoiceField(
        label=_("Driver"),
        choices=DRIVER_CHOICES,
        required=True,
        widget=django.forms.Select(attrs={
            'class': 'form-control switchable',
            'data-slug': 'driver',
        }),
    )

    ipmi_address = django.forms.IPAddressField(
        label=_("IPMI Address"),
        required=False,
        widget=django.forms.TextInput(attrs={
            'class': 'form-control switched',
            'data-switch-on': 'driver',
            'data-driver-pxe_ipmitool': _("IPMI Driver"),
        }),
    )
    ipmi_username = django.forms.CharField(
        label=_("IPMI User"),
        required=False,
        widget=django.forms.TextInput(attrs={
            'class': 'form-control switched',
            'data-switch-on': 'driver',
            'data-driver-pxe_ipmitool': _("IPMI Driver"),
        }),
    )
    ipmi_password = django.forms.CharField(
        label=_("IPMI Password"),
        required=False,
        widget=django.forms.PasswordInput(render_value=True, attrs={
            'class': 'form-control switched',
            'data-switch-on': 'driver',
            'data-driver-pxe_ipmitool': _("IPMI Driver"),
        }),
    )
    ssh_address = django.forms.IPAddressField(
        label=_("SSH Address"),
        required=False,
        widget=django.forms.TextInput(attrs={
            'class': 'form-control switched',
            'data-switch-on': 'driver',
            'data-driver-pxe_ssh': _("PXE + SSH"),
        }),
    )
    ssh_username = django.forms.CharField(
        label=_("SSH User"),
        required=False,
        widget=django.forms.TextInput(attrs={
            'class': 'form-control switched',
            'data-switch-on': 'driver',
            'data-driver-pxe_ssh': _("PXE + SSH"),
        }),
    )
    ssh_key_contents = django.forms.CharField(
        label=_("SSH Key Contents"),
        required=False,
        widget=django.forms.Textarea(attrs={
            'class': 'form-control switched',
            'data-switch-on': 'driver',
            'data-driver-pxe_ssh': _("PXE + SSH"),
            'rows': 2,
        }),
    )
    mac_addresses = tuskar_ui.forms.MultiMACField(
        label=_("NIC MAC Addresses"),
        required=True,
        widget=django.forms.Textarea(attrs={
            'placeholder': _('unspecified'),
            'rows': '2',
        }),
    )
    cpu_arch = django.forms.ChoiceField(
        label=_("Architecture"),
        required=False,
        choices=CPU_ARCH_CHOICES,
        widget=django.forms.Select(
            attrs={'placeholder': _('unspecified')}),
    )
    cpus = django.forms.IntegerField(
        label=_("CPUs"),
        required=False,
        min_value=0,
        widget=tuskar_ui.forms.NumberInput(
            attrs={'placeholder': _('unspecified')}),
    )
    memory_mb = django.forms.IntegerField(
        label=_("Memory"),
        required=False,
        min_value=0,
        widget=tuskar_ui.forms.NumberInput(
            attrs={'placeholder': _('unspecified')}),
    )
    local_gb = django.forms.IntegerField(
        label=_("Local Disk"),
        required=False,
        min_value=0,
        widget=tuskar_ui.forms.NumberInput(
            attrs={'placeholder': _('unspecified')}),
    )
    deployment_kernel = django.forms.ChoiceField(
        label=_("Kernel"),
        required=False,
        choices=[],
        widget=django.forms.Select(),
    )
    deployment_ramdisk = django.forms.ChoiceField(
        label=_("Ramdisk"),
        required=False,
        choices=[],
        widget=django.forms.Select(),
    )

    def get_name(self):
        try:
            name = (self.fields['ipmi_address'].value() or
                    self.fields['ssh_address'].value())
        except AttributeError:
            # when the field is not bound
            name = _("Undefined node")
        return name

    def handle(self, request, data):
        return create_node(request, data)

    def clean_ipmi_username(self):
        return self.cleaned_data.get('ipmi_username') or None

    def clean_ipmi_password(self):
        return self.cleaned_data.get('ipmi_password') or None

    def _require_field(self, field_name, cleaned_data):
        if cleaned_data.get(field_name):
            return
        self._errors[field_name] = self.error_class([_(
            u"This field is required"
        )])

    def clean(self):
        cleaned_data = super(NodeForm, self).clean()
        driver = cleaned_data['driver']

        if driver == 'pxe_ipmitool':
            self._require_field('ipmi_address', cleaned_data)
        elif driver == 'pxe_ssh':
            self._require_field('ssh_address', cleaned_data)
            self._require_field('ssh_username', cleaned_data)
            self._require_field('ssh_key_contents', cleaned_data)

        return cleaned_data


class BaseNodeFormset(tuskar_ui.forms.SelfHandlingFormset):
    def __init__(self, *args, **kwargs):
        self.kernel_images = kwargs.pop('kernel_images')
        self.ramdisk_images = kwargs.pop('ramdisk_images')
        super(BaseNodeFormset, self).__init__(*args, **kwargs)

    def add_fields(self, form, index):
        deployment_kernel_choices = [(kernel.id, kernel.name)
                                     for kernel in self.kernel_images]
        deployment_ramdisk_choices = [(ramdisk.id, ramdisk.name)
                                      for ramdisk in self.ramdisk_images]
        form.fields['deployment_kernel'].choices = deployment_kernel_choices
        form.fields['deployment_ramdisk'].choices = deployment_ramdisk_choices

    def clean(self):
        all_macs = api.node.Node.get_all_mac_addresses(self.request)
        bad_macs = set()
        bad_macs_error = _("Duplicate MAC addresses submitted: %s.")

        for form in self:
            if not form.cleaned_data:
                raise django.forms.ValidationError(
                    _("Please provide node data for all nodes."))

            new_macs = form.cleaned_data.get('mac_addresses')
            if not new_macs:
                continue
            new_macs = set(new_macs.split())

            # Prevent submitting duplicated MAC addresses
            # or MAC addresses of existing nodes
            bad_macs |= all_macs & new_macs
            all_macs |= new_macs

        if bad_macs:
            raise django.forms.ValidationError(
                bad_macs_error % ", ".join(bad_macs))


class UploadNodeForm(forms.SelfHandlingForm):
    csv_file = forms.FileField(label='', required=False)

    def handle(self, request, data):
        return True

    def get_data(self):
        try:
            output = utils.parse_csv_file(self.cleaned_data['csv_file'])
        except ValueError as e:
            messages.error(self.request, e.message)
            output = []

        return output


RegisterNodeFormset = django.forms.formsets.formset_factory(
    NodeForm, extra=1, formset=BaseNodeFormset)
