# Copyright (c) 2015 iXsystems, Inc.
# All rights reserved.
# This file is a part of TrueNAS
# and may not be copied and/or distributed
# without the express permission of iXsystems.

import logging
import os

from django.utils.translation import ugettext_lazy as _

from dojango import forms

from freenasUI.account.models import bsdUsers
from freenasUI.common.forms import Form, ModelForm
from freenasUI.middleware.client import client
from freenasUI.middleware.notifier import notifier
from freenasUI.network.models import Interfaces
from freenasUI.storage.models import Volume

from . import models

log = logging.getLogger('failover.forms')


class FailoverForm(ModelForm):

    class Meta:
        model = models.Failover
        fields = '__all__'

    def __init__(self, *args, **kwargs):
        super(FailoverForm, self).__init__(*args, **kwargs)
        if 'disabled' in self.fields:
            self.fields['disabled'].widget.attrs['onChange'] = (
                'toggleGeneric("id_disabled", ["id_master"], true);'
            )
        if 'master' in self.fields and ((
            self.instance.id and not self.instance.disabled
        ) or not self.instance.id):
            self.fields['master'].widget.attrs['disabled'] = 'disabled'

    def clean_disabled(self):
        disabled = self.cleaned_data.get('disabled')
        if disabled is False:
            if not Interfaces.objects.filter(int_critical=True).exists():
                raise forms.ValidationError(
                    _("You need at least one critical interface to enable failover")
                )
        return disabled

    def save(self, *args, **kwargs):
        if not self.instance.id:
            new = True
        else:
            new = False
        obj = super(FailoverForm, self).save(*args, **kwargs)
        if new:
            imported = False
            for vol in Volume.objects.all():
                try:
                    if notifier().zpool_parse(vol.vol_name):
                        imported = True
                        break
                except:
                    pass
            if imported:
                os.system('/usr/local/bin/python /usr/local/sbin/fenced force')
        return obj

    def done(self, *args, **kwargs):
        # Flip the system_failover.master value on the remote side.  This ensures that
        # one side has True and the other side has False.
        try:
            with client as c:
                c.call('failover.call_remote', 'datastore.sql', ["UPDATE system_failover SET master = %s", ["0"] if self.instance.master is True else ["1"]])
        except:
            # If this fails (for instance if the remote side is down) just journal
            # the SQL change and run it when the remote side comes back up.
            log.warn('Failed to set master/passive on standby node', exc_info=True)
        super(FailoverForm, self).done(*args, **kwargs)
        notifier().start("ix-devd")


class HAReplicationForm(Form):
    harepl_remote = forms.CharField(
        max_length=128,
        required=False,
        label=_('Remote Hostname'),
    )
    harepl_init = forms.BooleanField(
        initial=True,
        required=False,
        label=_('Initialize'),
    )

    def __init__(self, *args, **kwargs):
        super(HAReplicationForm, self).__init__(*args, **kwargs)
        harepl = notifier().harepl_get()
        if harepl:
            self.fields['harepl_remote'].initial = harepl[0]
            self.fields['harepl_init'].initial = harepl[1]

    def commit(self):
        notifier().harepl_set(
            remote=self.cleaned_data['harepl_remote'].__str__(),
            wantinit=self.cleaned_data['harepl_init'])


class TakeoverForm(Form):

    password = forms.CharField(
        label="Root Password",
        widget=forms.widgets.PasswordInput(),
    )

    def clean_password(self):
        pwd = self.cleaned_data.get('password')
        qs = bsdUsers.objects.filter(bsdusr_uid=0)
        if qs.exists():
            user = qs[0]
            if not user.check_password(pwd):
                raise forms.ValidationError('Password invalid!')
            return pwd
        raise forms.ValidationError('Root user not found')


class UnlockForm(TakeoverForm):

    passphrase = forms.CharField(
        label="Passphrase",
        widget=forms.widgets.PasswordInput(),
    )
