from django.shortcuts import render
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import login, authenticate
from django.http import FileResponse
from django.contrib.auth.decorators import login_required
from django.views.decorators.debug import sensitive_variables
from django.http import HttpResponseRedirect

from client.models import UserCode

import dateparser
import os
from io import BytesIO
from PIL import Image, UnidentifiedImageError
from pdf2image import convert_from_bytes
from pdf2image.exceptions import (
    PDFPageCountError,
    PDFSyntaxError
)

# override to remove help text
class RegisterForm(UserCreationForm):
    def __init__(self, *args, **kwargs):
        super(RegisterForm, self).__init__(*args, **kwargs)

        for fieldname in ['username', 'password1', 'password2']:
            self.fields[fieldname].help_text = None

@sensitive_variables("raw_passsword")
def signup(request):
    out_errors = []
    # signup form with terms
    if request.method == 'POST':
        # get form object
        form = RegisterForm(request.POST)

        # check if terms are accepted
        if "terms_accept" not in request.POST:
            out_errors.append("Accettare i termini e condizioni prego")

        # if form is valid and terms were accepted save user
        if form.is_valid() and len(out_errors) == 0:
            form.save()
            username = form.cleaned_data.get('username')
            raw_password = form.cleaned_data.get('password1')
            user = authenticate(username=username, password=raw_password)
            login(request, user)
            return HttpResponseRedirect('/')
        else:
            # get errors from form and add toasts
            errors = form.errors.as_data()
            for field in errors.keys():
                if field == "username":
                    out_errors.append("Il nome utente può contenere solo lettere e numeri")
                else:
                    password_errors = errors["password2"]
                    for err in password_errors:
                        if err.code == "password_mismatch":
                            out_errors.append("Le due password non sono uguali")
                        elif err.code == "password_too_similar":
                            out_errors.append("La password è troppo simile all'username")
                        elif err.code == "password_too_short":
                            out_errors.append("La password è troppo corta")
                        elif err.code == "password_too_common":
                            out_errors.append("La password è troppo comune")
                        elif err.code == "password_entirely_numeric":
                            out_errors.append("La password deve contenere lettere")

    else:
        # create empty form to be filled
        form = RegisterForm()

    context = {
        "form": form,
        "errors": out_errors,
    }
    return render(request, 'accounts/signup.html', context)


@login_required
def personal(request):
    context = {}
    # additional user informations
    usercode = UserCode.objects.filter(user=request.user)[0]
    # medical info
    medic = usercode.medic
    # values for multiple choice box
    # TODO remove multiple choice
    branca_default = ""
    branca_castorini = ""
    branca_lupetti = ""
    branca_esploratori = ""
    branca_pionieri = ""
    branca_rover = ""

    # variables for throwing errors to the user
    error = False
    error_text = ""

    if request.method == "POST":
        # requested download
        if request.POST['action'] == "download_vac":
            if medic.vac_certificate != None:
                filename = os.path.basename(medic.vac_certificate.name)
                filename = filename[filename.find("_")+1:]
                if filename.rfind('.') != -1:
                    filename = filename[:filename.rfind('.')]
                filename = filename + ".jpg"

                # encode in JPEG
                im = Image.open(medic.vac_certificate.file)
                im_io = BytesIO()
                im.save(im_io, 'JPEG', quality=90)
                im_io.seek(0)
                return FileResponse(im_io, as_attachment=True, filename=filename)

        if request.POST['action'] == "download_health":
            if medic.health_care_certificate != None:
                filename = os.path.basename(medic.health_care_certificate.name)
                filename = filename[filename.find("_")+1:]
                if filename.rfind('.') != -1:
                    filename = filename[:filename.rfind('.')]
                filename = filename + ".jpg"

                # encode in JPEG
                im = Image.open(medic.health_care_certificate.file)
                im_io = BytesIO()
                im.save(im_io, 'JPEG', quality=90)
                im_io.seek(0)
                return FileResponse(im_io, as_attachment=True, filename=filename)

        # set all attributes
        request.user.first_name = request.POST["first_name"]
        request.user.last_name = request.POST["last_name"]
        request.user.email = request.POST["email"]
        request.user.save()
        usercode.parent_name = request.POST["parent_name"]
        usercode.via = request.POST["via"]
        usercode.cap = request.POST["cap"]
        usercode.country = request.POST["country"]
        usercode.nationality = request.POST["nationality"]
        usercode.born_date = dateparser.parse(request.POST["birth_date"])
        usercode.home_phone = request.POST["home_phone"]
        usercode.phone = request.POST["phone"]
        usercode.school = request.POST["school"]
        usercode.avs_number = request.POST["avs_number"]
        if request.POST["year"].isdigit():
            usercode.year = request.POST["year"]
        else:
            error = True
            error_text = "L'anno scolastico deve essere un numero"

        usercode.save()

        medic.emer_name = request.POST["emer_name"]
        medic.emer_relative = request.POST["emer_relative"]
        medic.cell_phone = request.POST["cell_phone"]
        medic.address = request.POST["address"]
        medic.emer_phone = request.POST["emer_phone"]
        medic.health_care = request.POST["health_care"]
        medic.injuries = request.POST["injuries"]
        medic.rc = request.POST["rc"]
        medic.rega = "rega" in request.POST
        medic.medic_name = request.POST["medic_name"]
        medic.medic_phone = request.POST["medic_phone"]
        medic.medic_address = request.POST["medic_address"]
        medic.sickness = request.POST["sickness"]
        medic.vaccine = request.POST["vaccine"]
        medic.tetanus_date = dateparser.parse(request.POST["tetanus_date"])
        medic.allergy = request.POST["allergy"]
        medic.drugs_bool = "drugs_bool" in request.POST
        medic.drugs = request.POST["drugs"]
        medic.misc_bool = "misc_bool" in request.POST
        medic.misc = request.POST["misc"]
        medic.save()

        # if "branca" in request.POST:
        #    if request.POST["branca"] != "":
        #        request.user.groups.clear()
        #        request.user.groups.add(
        #            Group.objects.get(name=request.POST["branca"]))

        # check if user uploaded a file
        if "vac_certificate" in request.FILES:
            files = request.FILES.getlist('vac_certificate')
            name = files[0].name
            try:
                # if multiple files concatenate pictures
                im = Image.new("RGB", (0, 0), (255, 255, 255))
                for f in files:
                    if f.name.endswith(".pdf"):
                        images = convert_from_bytes(f.read())
                        for i in images:
                            dst = Image.new('RGB', (max(im.width, i.width), im.height + i.height), (255, 255, 255))
                            dst.paste(im, (0, 0))
                            dst.paste(i, (0, im.height))
                            im = dst
                    else:
                        i = Image.open(f)
                        dst = Image.new('RGB', (max(im.width, i.width), im.height + i.height), (255, 255, 255))
                        dst.paste(im, (0, 0))
                        dst.paste(i, (0, im.height))
                        im = dst

                im_io = BytesIO()
                # resize image if larger than max value
                if im.height > 16383:
                    im = im.resize((round(im.width/im.height*16383), 16383))
                # compress image in WEBP
                im.save(im_io, 'WEBP', quality=50, method=4)
                medic.vac_certificate.save(
                    request.user.username+"_"+name, im_io)
                medic.save()
            except UnidentifiedImageError:
                error = True
                error_text = "Il file non è un immagine valida"
            except PDFPageCountError:
                error = True
                error_text = "Il file non è un pdf valido"
            except PDFSyntaxError:
                error = True
                error_text = "Il file non è un pdf valido"
            except IOError:
                error = True
                error_text = "Il file è un immagine troppo grande"

        if "health_care_certificate" in request.FILES:
            files = request.FILES.getlist('health_care_certificate')
            name = files[0].name
            try:
                # if multiple files concatenate pictures
                im = Image.new("RGB", (0, 0), (255, 255, 255))
                for f in files:
                    if f.name.endswith(".pdf"):
                        images = convert_from_bytes(f.read())
                        for i in images:
                            dst = Image.new('RGB', (max(im.width, i.width), im.height + i.height), (255, 255, 255))
                            dst.paste(im, (0, 0))
                            dst.paste(i, (0, im.height))
                            im = dst
                    else:
                        i = Image.open(f)
                        dst = Image.new('RGB', (max(im.width, i.width), im.height + i.height), (255, 255, 255))
                        dst.paste(im, (0, 0))
                        dst.paste(i, (0, im.height))
                        im = dst

                im_io = BytesIO()
                # resize image if larger than max value
                if im.height > 16383:
                    im = im.resize((round(im.width/im.height*16383), 16383))
                # compress image in WEBP
                im.save(im_io, 'WEBP', quality=50, method=4)
                medic.health_care_certificate.save(
                    request.user.username+"_"+name, im_io)
                medic.save()
            except UnidentifiedImageError:
                error = True
                error_text = "Il file non è un immagine valida"
            except PDFPageCountError:
                error = True
                error_text = "Il file non è un pdf valido"
            except PDFSyntaxError:
                error = True
                error_text = "Il file non è un pdf valido"
            except IOError:
                error = True
                error_text = "Il file è un immagine troppo grande"

        # user requested file delete
        if request.POST["delete_vac"] == 'vac':
            medic.vac_certificate = None
            medic.save()

        if request.POST["delete_health"] == 'health':
            medic.health_care_certificate = None
            medic.save()

        # if there wasn't any error redirect to clear POST
        if not error:
            return HttpResponseRedirect("")

    # check if user is in a group and set multiple choice to that
    if len(request.user.groups.values_list('name', flat=True)) == 0:
        branca_default = "selected"
    else:
        parent_group = request.user.groups.values_list('name', flat=True)[
            0]
        if parent_group == "colonia":
            branca_castorini = "selected"
        elif parent_group == "muta":
            branca_lupetti = "selected"
        elif parent_group == "reparto":
            branca_esploratori = "selected"
        elif parent_group == "posto":
            branca_pionieri = "selected"
        elif parent_group == "clan":
            branca_rover = "selected"
        else:
            branca_default = "selected"

    # set checkbox status
    rega = ""
    if medic.rega:
        rega = "checked='checked'"
    drugs = ""
    if medic.drugs_bool:
        drugs = "checked='checked'"
    misc = ""
    if medic.misc_bool:
        misc = "checked='checked'"

    # set file name for uploaded files
    if (medic.vac_certificate != None):
        vac_name = os.path.basename(medic.vac_certificate.name)
        vac_name = vac_name[vac_name.find("_")+1:]
    else:
        vac_name = ''

    if (medic.health_care_certificate != None):
        card_name = os.path.basename(medic.health_care_certificate.name)
        card_name = card_name[card_name.find("_")+1:]
    else:
        card_name = ''

    # fill context
    context = {
        'first_name': request.user.first_name,
        'last_name': request.user.last_name,
        'email': request.user.email,
        'parent_name': usercode.parent_name,
        'via': usercode.via,
        'cap': usercode.cap,
        'country': usercode.country,
        'nationality': usercode.nationality,
        'birth_date': usercode.born_date,
        'home_phone': usercode.home_phone,
        'phone': usercode.phone,
        'school': usercode.school,
        'year': usercode.year,
        'avs_number': usercode.avs_number,
        'branca_default': branca_default,
        'branca_castorini': branca_castorini,
        'branca_lupetti': branca_lupetti,
        'branca_esploratori': branca_esploratori,
        'branca_pionieri': branca_pionieri,
        'branca_rover': branca_rover,
        'emer_name': medic.emer_name,
        'emer_relative': medic.emer_relative,
        'cell_phone': medic.cell_phone,
        'address': medic.address,
        'emer_phone': medic.emer_phone,
        'health_care': medic.health_care,
        'injuries': medic.injuries,
        'rc': medic.rc,
        'rega_check': rega,
        'medic_name': medic.medic_name,
        'medic_phone': medic.medic_phone,
        'medic_address': medic.medic_address,
        'sickness': medic.sickness,
        'vaccine': medic.vaccine,
        'tetanus_date': medic.tetanus_date,
        'allergy': medic.allergy,
        'drugs_check': drugs,
        'drugs': medic.drugs,
        'misc_check': misc,
        'misc': medic.misc,
        'health_care_certificate': card_name,
        'vac_certificate': vac_name,
        'error': error,
        'error_text': error_text,
    }

    return render(request, 'accounts/index.html', context)


# simple terms page, only static html
def terms(request):
    context = {}
    return render(request, 'accounts/terms.html', context)