# 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 cgi
import json
import logging
import os
import socket
import struct

from django.http import HttpResponse
from django.shortcuts import render
from django.utils.translation import ugettext as _

from freenasUI.common.system import get_sw_version
from freenasUI.freeadmin.middleware import public
from freenasUI.freeadmin.views import JsonResp
from freenasUI.network.forms import IPMIForm
from freenasUI.middleware.client import client, ClientException
from freenasUI.middleware.exceptions import MiddlewareError
from freenasUI.middleware.notifier import notifier
from . import forms

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

SW_VERSION = get_sw_version(True)


def failovers_sync_peer(request, fromto):

    # FIXME: import from tools.alert
    SYNC_FILE = '/var/tmp/sync_failed'

    if request.method == "POST":
        if fromto == "to" and os.path.exists(SYNC_FILE):
            os.unlink(SYNC_FILE)
        try:
            failover = notifier().failover_sync_peer(fromto=fromto)
            assert failover is not False
            try:
                if request.POST.get('standby_reboot'):
                    with client as c:
                        c.call('failover.call_remote', 'system.reboot', [{'delay': 2}])
            except Exception:
                log.warn('Failed to reboot standby node', exc_info=True)
                raise MiddlewareError(_('Failed to reboot standby node.'))
            return JsonResp(
                request,
                message=_("You have successfully synced %s peer.") % (
                    fromto,
                )
            )
        except Exception as e:
            if fromto == "to":
                open(SYNC_FILE, 'w').close()
            return JsonResp(
                request,
                error=True,
                message='An error occured: %s' % cgi.escape(str(e)),
            )
    else:
        return render(
            request,
            "system/failover_sync_%s_peer.html" % (fromto),
            {'ip': notifier().failover_pair_ip()},
        )


@public
def failover_disabled(request):
    reasons = notifier().failover_disabled_reasons()
    return HttpResponse(
        json.dumps(reasons),
        content_type='application/json',
    )


def failover_disabled_detail(request):
    reasons = notifier().failover_disabled_reasons()
    return render(request, "failover/disabled.html", {
        'reasons': reasons,
    })


@public
def failovers_status(request):
    if not hasattr(notifier, 'failover_status'):
        status = ''
    else:
        status = notifier().failover_status()
    return HttpResponse(status)


def failovers_force_master(request):
    ret = notifier().failover_force_master()
    if ret:
        return JsonResp(request, message='Failover force master initiated')
    else:
        return JsonResp(request, message='Failover force master failed')


def waitnode(request):

    data = 'WAITING'
    try:
        with client as c:
            ready = c.call('failover.call_remote', 'system.ready')
            if ready:
                version = c.call('failover.call_remote', 'system.version')
                data = 'UPDATE'
                if version:
                    if version == SW_VERSION:
                        data = 'FINISHED'
    except ClientException:
        pass

    return HttpResponse(
        json.dumps(data),
        content_type='application/json',
    )


def hareplication(request):
    if request.method == 'POST':
        form = forms.HAReplicationForm(request.POST)
        if form.is_valid():
            form.commit()
            return JsonResp(
                request,
                message=_("HA Replication successfully updated.")
            )
    else:
        form = forms.HAReplicationForm()
    return render(request, 'storage/hareplication.html', {
        'form': form,
    })


@public
def takeover(request):

    form = forms.TakeoverForm(request.POST)
    error = True
    message = ''
    if form.is_valid():
        error = False
        notifier().failover_force_master()
    else:
        for field, value in list(form.errors.items()):
            message += str(value)

    return HttpResponse(json.dumps({
        'error': error,
        'message': message,
    }))


@public
def unlock(request):

    form = forms.UnlockForm(request.POST)
    error = True
    message = ''
    if form.is_valid():
        error = False
        with client as c:
            c.call('failover.encryption_setkey', form.cleaned_data.get('passphrase'))
        notifier().failover_force_master()
    else:
        for field, value in list(form.errors.items()):
            if field != '__all__':
                message += field + ': '
            message += str(value)

    return HttpResponse(json.dumps({
        'error': error,
        'message': message,
    }))


def ipmi(request):

    class IPMIFormB(IPMIForm):
        pass

    if request.method == "POST":
        form = IPMIFormB(request.POST, remote=True, auto_id='idb_%s')
        if form.is_valid():
            if form.save() == 0:
                return JsonResp(request, message=_("IPMI successfully edited"))
            else:
                return JsonResp(request, error=True, message=_("IPMI failed"))
    else:
        form = IPMIFormB(remote=True, auto_id='idb_%s')
    return render(request, 'network/ipmi.html', {
        'form': form,
    })
