# -*- coding: utf-8 -*-

import locale

from gsxws import GsxError

from django.conf import settings
from django.contrib import messages
from django.core.cache import cache

from django.utils import translation
from django.utils.translation import ugettext as _
from django.views.decorators.cache import never_cache
from django.shortcuts import render, redirect, get_object_or_404
from django.core.exceptions import ValidationError, PermissionDenied

from servo.lib.utils import json_response
from servo.views.order import put_on_paper
from servo.validators import apple_sn_validator
from servo.exceptions import ConfigurationError
from servo.models import (User, Device, GsxAccount, Order,
                          Customer, Location, Note, Attachment,
                          Configuration, ChecklistItem, Tag,)
from servo import forms


def find_device(request):
    device = Device(sn=request.GET['sn'])
    device.description = _('Other Device')
    device_form = forms.DeviceForm(instance=device)

    try:
        apple_sn_validator(device.sn)
    except Exception as e:  # not an Apple serial number
        return render(request, "checkin/device_form.html", locals())

    try:
        device = get_device(request, device.sn)
        device_form = forms.DeviceForm(instance=device)
    except GsxError as e:
        error = e

    return render(request, "checkin/device_form.html", locals())


def find_customer(request, phone):
    if not request.user.is_authenticated():
        raise PermissionDenied

    results = []

    for c in Customer.objects.filter(phone=phone):
        title = '%s - %s' % (c.phone, c.name)
        results.append({'id': c.pk, 'name': c.name, 'title': title})

    return json_response(results)


def init_locale(request):
    """Initialize locale for the check-in interface."""
    lc = settings.INSTALL_LOCALE.split('.')
    locale.setlocale(locale.LC_TIME, lc)
    locale.setlocale(locale.LC_NUMERIC, lc)
    locale.setlocale(locale.LC_MESSAGES, lc)
    locale.setlocale(locale.LC_MONETARY, lc)

    translation.activate(settings.INSTALL_LANGUAGE)
    request.session[translation.LANGUAGE_SESSION_KEY] = settings.INSTALL_LANGUAGE


def set_cache_device(device):
    key = 'checkin-device-%s' % device.sn
    cache.set(key, device)


def get_gsx_connection(request):
    act = GsxAccount.get_default_account()
    user = User.objects.get(pk=request.session['checkin_user'])
    location = Location.objects.get(pk=request.session['checkin_location'])
    return act.connect(user, location)


def get_remote_device(request, sn):
    try:
        apple_sn_validator(sn)
    except ValidationError:
        return Device(sn=sn, image_url='https://static.servoapp.com/images/na.gif')

    get_gsx_connection(request)

    return Device.from_gsx(sn)


def get_local_device(request, sn):
    try:
        device = Device.objects.filter(sn=sn)[0]
    except IndexError:
        device = get_remote_device(request, sn)

    return device


def get_device(request, sn):
    if len(sn) < 1:
        return Device(sn=sn)

    key = 'checkin-device-%s' % sn
    device = cache.get(key, get_local_device(request, sn))
    set_cache_device(device)
    return device


def init_session(request):
    """
    Initialize the session for the check-in interface.

    Only run for GET requests
    """
    if not request.user.is_authenticated():
        request.session.flush()

    if not Configuration.checkin_enabled():
        raise ConfigurationError(_('Check-in interface not enabled'))

    # initialize locale
    init_locale(request)

    # set test cookie
    request.session.set_test_cookie()

    # initialize vars
    request.session['checkin_device'] = None
    request.session['checkin_customer'] = None

    user = User.get_checkin_user()
    location = user.location

    if not request.session.get('company_name'):
        request.session['company_name'] = Configuration.conf('company_name')

    if request.user.is_authenticated():

        # these are our fallback defaults
        user = request.user
        location = user.location

        try:
            location_id = request.GET['l']
        except KeyError:
            # not given - try session, then default to user's location
            location_id = request.session.get('checkin_location', location.pk)
        finally:
            location = get_object_or_404(Location, pk=location_id)

        try:
            user_id = request.GET['u']
        except KeyError:
            # not given - default to session, then auth user
            user_id = request.session.get('checkin_user', user.pk)

        user = get_object_or_404(User, pk=user_id)
        request.session['checkin_locations'] = Location.get_checkin_list()

        checkin_users = User.get_checkin_group()
        queryset = checkin_users.filter(location=location)
        request.session['checkin_users'] = User.serialize(queryset)

    request.session['checkin_user'] = user.pk
    request.session['checkin_location'] = location.pk
    request.session['checkin_user_name'] = user.get_name()
    request.session['checkin_location_name'] = location.title


def reset(request):
    init_session(request)
    return redirect(index)


def thanks(request, order):
    """
    Final step/confirmation
    """
    title = _('Done!')

    try:
        order = Order.objects.get(url_code=order)
    except Order.DoesNotExist:
        messages.error(request, _('Order does not exist'))
        return redirect(reset)

    return render(request, "checkin/thanks.html", locals())


def get_customer(request):
    """Return the selected customer data."""
    if not request.user.is_authenticated():
        raise PermissionDenied

    if not request.GET.get('c'):
        return

    customer = get_object_or_404(Customer, pk=request.GET['c'])
    request.session['checkin_customer'] = customer.pk

    fdata = {'fname': customer.firstname, 'lname': customer.lastname}
    fdata['city'] = customer.city
    fdata['email'] = customer.email
    fdata['phone'] = customer.phone
    fdata['country'] = customer.country
    fdata['postal_code'] = customer.zip_code
    fdata['address'] = customer.street_address

    return json_response(fdata)


def status(request):
    """Check service order status through the checkin."""
    title = _('Repair Status')

    if request.GET.get('code'):
        timeline = []
        form = forms.StatusCheckForm(request.GET)
        if form.is_valid():
            code = form.cleaned_data['code']
            try:
                order = Order.objects.get(code=code)
                status_description = order.get_status_description()
                if Configuration.conf('checkin_timeline'):
                    timeline = order.orderstatus_set.all()
                if order.status is None:
                    order.status_name = _(u'Waiting to be processed')
            except Order.DoesNotExist:
                messages.error(request, _(u'Order %s not found') % code)
            return render(request, "checkin/status-show.html", locals())
    else:
        form = forms.StatusCheckForm()

    return render(request, "checkin/status.html", locals())


def print_confirmation(request, code):
    """Output the order confirmation to the user."""
    order = get_object_or_404(Order, url_code=code)
    return put_on_paper(request, order.pk)


def terms(request):
    """Show terms of service."""
    conf = Configuration.conf()
    return render(request, 'checkin/terms.html', locals())


@never_cache
def index(request):
    """
    Render the checkin homepage.

    @FIXME: would be nice to break this into smaller chunks...
    """
    if request.method == 'GET':
        try:
            init_session(request)
        except ConfigurationError as e:
            error = {'message': e}
            return render(request, 'checkin/error.html', error)

    title = _('Service Order Check-In')
    dcat = request.GET.get('d', 'mac')
    dmap = {
        'mac': _('Mac'),
        'iphone': _('iPhone'),
        'ipad': _('iPad'),
        'ipod': _('iPod'),
        'acc': _('Apple Accessory'),
        'beats': _('Beats Products'),
        'other': _('Other Devices'),
    }

    issue_form = forms.IssueForm()
    device = Device(description=dmap[dcat])

    if dcat in ('mac', 'iphone', 'ipad', 'ipod'):
        sn_form = forms.AppleSerialNumberForm()
    else:
        sn_form = forms.SerialNumberForm()

    tags = Tag.objects.filter(type="order")
    device_form = forms.DeviceForm(instance=device)
    customer_form = forms.CustomerForm(request)

    if request.method == 'POST':

        if not request.session.test_cookie_worked():
            error = {'message': _('Please enable cookies to use this application.')}
            return render(request, 'checkin/error.html', error)
        else:
            request.session.delete_test_cookie()

        sn_form = forms.SerialNumberForm(request.POST)
        issue_form = forms.IssueForm(request.POST, request.FILES)
        customer_form = forms.CustomerForm(request, request.POST)
        device_form = forms.DeviceForm(request.POST, request.FILES)

        if device_form.is_valid() and issue_form.is_valid() and customer_form.is_valid():

            user = get_object_or_404(User, pk=request.session['checkin_user'])

            idata = issue_form.cleaned_data
            ddata = device_form.cleaned_data
            cdata = customer_form.cleaned_data
            customer_id = request.session.get('checkin_customer')

            if customer_id:
                customer = get_object_or_404(Customer, pk=customer_id)
            else:
                customer = Customer()

            name = u'{0} {1}'.format(cdata['fname'], cdata['lname'])

            if len(cdata['company']):
                name += ', ' + cdata['company']

            customer.name = name
            customer.city = cdata['city']
            customer.phone = cdata['phone']
            customer.email = cdata['email']
            customer.phone = cdata['phone']
            customer.zip_code = cdata['postal_code']
            customer.street_address = cdata['address']
            customer.save()

            order = Order(customer=customer, created_by=user)
            order.location_id = request.session['checkin_location']
            order.checkin_location = cdata['checkin_location']
            order.checkout_location = cdata['checkout_location']

            order.save()
            order.check_in(user)

            try:
                device = get_device(request, ddata['sn'])
            except GsxError as e:
                pass

            device.username = ddata['username']
            device.password = ddata['password']
            device.description = ddata['description']
            device.purchased_on = ddata['purchased_on']
            device.purchase_country = ddata['purchase_country']
            device.save()

            order.add_device(device, user)

            note = Note(created_by=user, body=idata['issue_description'])
            note.is_reported = True
            note.order = order
            note.save()

            # Proof of purchase was supplied
            if ddata.get('pop'):
                f = {'content_type': Attachment.get_content_type('note').pk}
                f['object_id'] = note.pk
                a = forms.AttachmentForm(f, {'content': ddata['pop']})
                a.save()

            if request.POST.get('tags'):
                order.set_tags(request.POST.getlist('tags'), request.user)

            # Check checklists early for validation
            answers = []

            # @FIXME: should try to move this to a formset...
            for k, v in request.POST.items():
                if k.startswith('__cl__'):
                    answers.append('- **' + k[6:] + '**: ' + v)

            if len(answers) > 0:
                note = Note(created_by=user, body="\r\n".join(answers))

                if Configuration.true('checkin_report_checklist'):
                    note.is_reported = True

                note.order = order
                note.save()

            # mark down internal notes (only if logged in)
            if len(idata.get('notes')):
                note = Note(created_by=user, body=idata['notes'])
                note.is_reported = False
                note.order = order
                note.save()

            # mark down condition of device
            if len(ddata.get('condition')):
                note = Note(created_by=user, body=ddata['condition'])
                note.is_reported = True
                note.order = order
                note.save()

            # mark down supplied accessories
            if len(ddata.get('accessories')):
                accs = ddata['accessories'].strip().split("\n")
                order.set_accessories(accs, device)

            redirect_to = thanks

            # Move to custom queue, if set
            if device_form.cleaned_data.get('queue'):
                order.set_queue(device_form.cleaned_data['queue'], user)

            """
            if request.user.is_authenticated():
                if request.user.autoprint:
                    redirect_to = print_confirmation
            """
            return redirect(redirect_to, order.url_code)

    try:
        pk = Configuration.conf('checkin_checklist')
        questions = ChecklistItem.objects.filter(checklist_id=pk)
    except ValueError:
        # Checklists probably not configured
        pass

    if request.GET.get('phone'):
        return find_customer(request, request.GET['phone'])

    if request.GET.get('sn'):
        return find_device(request)

    return render(request, "checkin/newindex.html", locals())