# -*- encoding: utf-8 -*-

from datetime import date, datetime, timedelta       # timeSlices
from collections import OrderedDict
import csv

import django
from django.http import HttpResponse, HttpResponseRedirect
from django.template import Template, RequestContext, loader
from django.shortcuts import render, redirect

from django.contrib.auth.decorators import login_required
from django.urls import reverse  
from django.views.decorators.csrf import ensure_csrf_cookie
from django import forms
from django.forms import ModelForm
from django.contrib import messages
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import pgettext, pgettext_lazy

from django.db import transaction
from django.db.models import F

from django.core.exceptions import ValidationError

import logging

from django.conf import settings as appSettings

from . import models
from . import forms
from . import auth as nalodeni_auth

# Logger instance
logger = logging.getLogger(__name__)

def role_required(roles=[]):
    def decorate(func):
        def call(request, *args, **kwargs):
            for r in roles:
                if not r in request.session['site_perms']:
                    messages.error(request, "Nedostatečné oprávnění pro přístup. Detaily byly zaznamenány.")
                    return HttpResponseRedirect('/')
            result = func(request, *args, **kwargs)
            return result
        return call
    return decorate

def get_AppUser_objects(request):
    ''' Zkontroluje, že všechny objekty v 'objs' vyhovují přiděleným rolím.
        Nevyhovující vyřadí.
    '''
    sp = request.session['site_perms']
    if 'sso_kodo' not in sp:
        return models.AppUser.objects.none()

    if 'sso_admin' in sp:
        return models.AppUser.objects.all()

    objs = models.AppUser.objects.filter(district__in=request.session['spc']['dist'])

    return objs

def get_AppUser_districts(request):
    '''Vrátí dostupné kraje podle rolí.'''


    if 'sso_admin' in request.session['site_perms']:
        return list(models.AppUser.DISTRICT_CHOICES)

    rslt = []
    for d in models.AppUser.DISTRICT_CHOICES:
        if d[0] in request.session['spc']['dist']:
            rslt.append(d)

    return rslt
    

@ensure_csrf_cookie
@login_required(login_url="/prihlaseni")
@role_required(['sso_kodo'])
def confirmed(request, newOnly=False, dist=None):
    if dist is None:
        dist = int(request.POST.get('dist', -1))
    doCsvExport = None != request.POST.get('doCsvExport', None)

    objs = get_AppUser_objects(request).order_by('last_name', 'first_name' ,'email')

    if newOnly:
        objs = objs.filter(status=models.AppUser.STATUS_NEW)
    else:
        objs = objs.filter(status=models.AppUser.STATUS_REG)

    districts = [(-1, ' -- vše dostupné -- ')] + get_AppUser_districts(request)
    # filtrujeme jen povolene kraje, nebo vse pro adminy
    if dist != -1 and (dist in request.session['spc']['dist'] or 'sso_admin' in request.session['site_perms']):
        selDist = dist
        objs = objs.filter(district=selDist)
    else:
        selDist = -1

    if doCsvExport:
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = 'attachment; filename="nalodeni-kraj-%s-%s.csv"' % (selDist, date.today())

        row_headers = [
            "ID",
            "Jméno",
            "Příjmení",
            "E-mail registrační",
            "E-mail kontaktní",
            "Kraj",
            "PSČ",
            "Město",
            "Druh",
            "Poznámka",
            "Stav",
            "Datum souhlasu o.ú.",
            "Poznámka dovednosti",
            ]
        col_count = len(row_headers)
        row_nums = {}

        for abbr, mdl in [
                ('IR',models.InterestRegion ),
                ('US',models.UserSkill ),
                ('UT',models.UserTopic ), ]:
            for i in mdl.objects.all():
                row_nums[abbr+'_'+str(i.id)] = col_count
                row_headers.append(i.name)
                col_count += 1

        writer = csv.writer(response)
        writer.writerow(row_headers)
        for obj in objs:
            row = len(row_headers) * [None]
            row[0] = obj.id
            row[1] = obj.first_name
            row[2] = obj.last_name
            row[3] = obj.email
            row[4] = obj.email_contact_active
            row[5] = obj.DISTRICT_CHOICES_STR[obj.district]
            row[6] = obj.postcode
            row[7] = obj.city
            row[8] = obj.KIND_CHOICES_STR[obj.kind]
            row[9] = obj.interestedIn
            row[10] = obj.STATUS_CHOICES_STR[obj.status]
            row[11] = obj.dc_stamp
            row[12] = obj.userform.skills_note if obj.userform else None

            if obj.userform:
                for abbr, mdl in [
                        ('IR', obj.userform.regions ),
                        ('US', obj.userform.skills ),
                        ('UT', obj.userform.topics ), ]:
                    for i in mdl.all():
                        row[row_nums[abbr+"_"+str(i.id)]] = "x"

            writer.writerow(row)

        return response
        

    template = 'people/list.html'
    context = {
        'people' : objs,
        'newOnly' : newOnly,
        'distAvail' : districts,
        'selDist' : selDist,
        }

    return render(request, template, context)


@ensure_csrf_cookie
@login_required(login_url="/prihlaseni")
@role_required(['sso_kodo'])
def pending(request):
    ''' List pending registrations from AppRegEmail. '''

    show_all = request.GET.get("show_all","no") == "yes"

    if request.method == "POST":
        act = request.POST.get("action", None)
        ids = request.POST.getlist('r[]')

        objs = models.AppRegEmail.objects.filter(id__in = ids)

        if act == "token":
            email_counter = 0
            skipped_counter = 0
            for o in objs:
                # kontrola, jestli uživatel již není registrován
                rslt = models.AppUser.objects.filter(email__iexact=o.email.strip())
                if len(rslt) != 0:
                    messages.info(request,'Uživatel s emailem %s již je registrován, požadavek na registaci odstraněn.' % o.email)
                    o.delete()
                else:
                    if not ( o.etStamp and (datetime.now() - o.etStamp).total_seconds() < int(appSettings.TOKEN_VALID_SEC)):
                        # token not valid or not sent
                        nalodeni_auth.sendRegisterToken(o.email)
                        email_counter += 1
                    else:
                        skipped_counter += 1
            if email_counter > 0:
                messages.info(request,'Registrační emaily odeslány, celkem odesláno %s zpráv.' % email_counter)
            if skipped_counter > 0:
                messages.info(request,'Celkem %s registrací přeskočeno, ještě jsou platné.' % skipped_counter)
            
        elif act == "delete":
            objs.delete()
            messages.info(request,'Registrace odstraněny.')

    tokenValidAfter = datetime.now() - timedelta(seconds=int(appSettings.TOKEN_VALID_SEC))

    objs = models.AppRegEmail.objects.all()
    if not show_all:
        # zobrazovat pouze nové registrace
        objs = objs.filter(emailToken = None)
    objs = objs.order_by('etStamp')

    template = 'people/pending.html'
    context = {
        'people' : objs,
        'tokenValidAfter' : tokenValidAfter,
        'show_all' : show_all,
        }

    return render(request, template, context)



@ensure_csrf_cookie
@login_required(login_url="/prihlaseni")
@role_required(['sso_kodo'])
def update(request):
    ids = request.POST.getlist('r[]')
    val = request.POST.get('setStatus', None)

    if val and val in ['reg','new']:
        objs = get_AppUser_objects(request).filter(id__in=ids)

        rec = 0
        for o in objs:
            rec += 1
            o.status = o.STATUS_REG if val == 'reg' else o.STATUS_NEW
            o.save()

            messages.info(request, 'Upraveno celkem %s záznamů.' % rec)

        if val == 'new':
            return HttpResponseRedirect('/people/list/')
        elif val == "reg":
            return HttpResponseRedirect('/people/list-new/')
    else:
        messages.error(request, 'Špatný požadavek.')
    

    return HttpResponseRedirect('/people/list/')


@login_required(login_url="/prihlaseni")
@transaction.atomic
@role_required(['sso_kodo'])
def person_detail(request, id):
    obj = models.USER_MODEL.objects.get(pk=id)

    sp = request.session['site_perms']
    sp_sso_kodo = 'sso_kodo' in sp
    sp_sso_admin = 'sso_admin' in sp

    # Check permissions to edit this object
    if not sp_sso_admin and not obj.district in get_AppUser_districts(request):
        messages.error(request, 'K tomuto záznamu nemáte přístup. ')
        return redirect('nalodeni:people_list')

    template = 'person/detail.html'
    context = {
        'obj' : obj,
    }

    return render(request, template, context)

@login_required(login_url="/prihlaseni")
@transaction.atomic
@role_required(['sso_kodo'])
def person_edit(request, id):
    obj = models.USER_MODEL.objects.get(pk=id)
    
    sp = request.session['site_perms']
    sp_sso_kodo = 'sso_kodo' in sp
    sp_sso_admin = 'sso_admin' in sp

    # Check permissions to edit this object
    if not sp_sso_admin and not obj.district in get_AppUser_districts(request):
        messages.error(request, 'K tomuto záznamu nemáte přístup. ')
        return redirect('nalodeni:people_list')

    if obj.ssoUid:
       _form = forms.AppUserSsoForm
    else:
       _form = forms.AppUserForm

    if request.method == "GET":
        form = _form(instance=obj)
        form.fields['email_contact'].disabled = True
        form.fields['postcode'].required = False

    elif request.method == "POST":
        with obj.audit_context(request.user) as ac:
            form = _form(request.POST, instance=obj)
            form.fields['email_contact'].disabled = True
            form.fields['postcode'].required = False
            if form.is_valid():
                form.save()

                messages.info(request, "Údaje byly uloženy.")
                return redirect('nalodeni:person_detail', form.instance.id)

            else:
                messages.error(request, "Opravte prosím chyby v zadání.")
                raise ac.DataNotSavedException
    else:
        form = None

    template = 'person/edit.html'
    context = {
            'obj' : obj,
            'form' : form,
            'AUTH_SERVER' : appSettings.AUTH_SERVER,
        }

    return render(request, template, context)


