from rest_framework import viewsets, permissions
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser
from health_view.serializers import *
from health_view.crypto_functions import *
from datetime import datetime
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAdminUser
from rest_framework.response import Response
import json


@csrf_exempt
def get_key(request, name, part_name="", justified=""):
    user_obj = User.objects.get(username=name)
    justified_obj = User.objects.get(username=justified)
    folderinfo = user_obj.folderinfo
    folderpart_obj = FolderPart.objects.get(part_class=part_name, folder_id=folderinfo)
    key = JustifiedKey.objects.filter(justified_name=justified_obj, part=folderpart_obj).first()
    if request.method == 'GET':
        serializer = KeySerializer(key)
        return JsonResponse(serializer.data)
    elif request.method == 'POST':
        data = JSONParser().parse(request)
        serializer = KeySerializer(key, data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data, status=201)
        return JsonResponse(serializer.errors, status=400)


@csrf_exempt
def get_content(request, name, part_name=""):
    user_obj = User.objects.get(username=name)
    folderinfo = user_obj.folderinfo
    folderpart_obj = FolderPart.objects.get(part_class=part_name, folder_id=folderinfo)
    if request.method == 'GET':
        serializer = ContentSerializer(folderpart_obj)
        return JsonResponse(serializer.data)
    elif request.method == 'POST':
        data = json.loads(request.body)
        serializer = ContentSerializer(folderpart_obj, data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data, status=201)
        return JsonResponse(serializer.errors, status=400)


def create_signature_string(license):
    signature_string = license["patient"] + "&" + license["justified"] + "&" + license["creator"] + "&" + license["expdate"].replace(" ", ",") + "&" + license["permissions"] + "&" + license["folderparts"]
    signature_string = signature_string.replace(" ", "")
    return signature_string


def create_signature_string_certificate(license):
    signature_string = license["patient"] + "&" + license["justified"] + "&" + license["creator"] + "&" + license["expdate"].replace(" ", ",")  + "&" + license["permissions"] + "&" + license["folderparts"] + "&" + license["signature"] + "&" + license['content_key']
    signature_string = signature_string.replace(" ", "")
    return signature_string


def get_creator(license):
    creator = User.objects.get(username=license["creator"])
    return creator


def get_pubkey(user):
    pubkey = user.folderinfo.pub_key
    return pubkey


def check_expiration_date(license):
    exp_date = license["expdate"]
    print(exp_date)
    for fmt in ('%d-%m-%Y %H:%M', '%d/%m/%Y %H:%M', '%d/%m/%Y', '%d-%m-%Y'):
        try:
            datetime_object = datetime.strptime(exp_date, fmt)
            break
        except ValueError:
            pass
    try:
        return datetime.now() < datetime_object
    except Exception:
        return False


def check_permissions(license, part, permission):
    if part == "":
        return True
    if permission not in license["permissions"]:
        return False
    if part not in license["folderparts"]:
        return False
    return True


def check_change_siganture(pubkey, user_sign, datetime_given, content):
    message = datetime_given + "|" + content
    if verify(message, user_sign, pubkey):
        return True
    return False


def check_license(license, folderpart="", permission=""):
    creator = get_creator(license)
    if not verify(create_signature_string(license), license['signature'], get_pubkey(creator)):
        return False
    if not verify(create_signature_string_certificate(license), license['serversign'], pub_key_licenseserver):
        return False
    if not check_expiration_date(license):
        return False
    if not check_permissions(license, folderpart, permission):
        return False
    return True


@csrf_exempt
def read_folder(request):
    if request.method == 'POST':
        data = json.loads(request.body)
        license = data[0]
        folderpart = data[1]
        if not check_license(license, folderpart, "Read"):
            return HttpResponse(status=404)
        content_key = license['content_key']
        content_key_decrypted = decrypt(content_key)
        patient = User.objects.get(username=license["patient"])
        part_class = FolderPart_Name.objects.get(part_name=folderpart)
        part = FolderPart.objects.get(folder_id=patient.folderinfo, part_class=part_class)
        justified = User.objects.get(username=license["justified"])
        pubkey_justified = justified.folderinfo.pub_key
        if len(data) == 3:
            justified = User.objects.get(username=license["creator"])
        key_obj = JustifiedKey.objects.get(part=part, justified_name=justified)
        content = part.part_context
        decrypt_content = decrypt_aes(content, content_key_decrypted)
        response_obj = {'content': decrypt_content,
                    'key': key_obj.key,
                    'pubkey': pubkey_justified}
        return JsonResponse(response_obj, status=201)


@csrf_exempt
def write_folder(request):
    if request.method == 'POST':
        data = json.loads(request.body)
        license = data[0]
        folderpart = data[1]
        content = data[2]
        datetime_given = data[3]
        user_sign = data[4]
        if not check_license(license, folderpart, "Write"):
            return HttpResponse(status=404)
        content_key = license['content_key']
        datetime_given_formatted = datetime.strptime(datetime_given, '%Y-%m-%d|%H:%M:%S')
        date_difference = datetime.now() - datetime_given_formatted
        content_key_decrypt = decrypt(content_key)
        patient = User.objects.get(username=license["patient"])
        part_class = FolderPart_Name.objects.get(part_name=folderpart)
        part = FolderPart.objects.get(folder_id=patient.folderinfo, part_class=part_class)
        justified = User.objects.get(username=license["justified"])
        if date_difference.seconds//60.0 > 4.0 or not check_change_siganture(get_pubkey(justified), user_sign, datetime_given, content):
            return HttpResponse(status=404)
        content = folderpart + content
        part.part_context = encrypt_aes(content, content_key_decrypt)
        if JustifiedKey.objects.filter(part=part, justified_name=justified).exists():
            part.save()
        json_obj = {'works': 'fined'}
        return JsonResponse(json_obj, status=201)


@csrf_exempt
def create_new_folder(request):
    if request.method == 'POST':
        data = json.loads(request.body)
        print(data)
        license = data[0]
        if not check_license(license):
            return HttpResponse(status=404)
        content_key = license['content_key']
        content_key_decrypt = decrypt(content_key)
        patient = User.objects.get(username=license["patient"])
        for c in range(1, len(data)):
            part_class = data[c]["part_class"]
            content = data[c]["content"]
            content = part_class + content
            encrypted_key = data[c]["encrypted_key"]
            encrypted_content = encrypt_aes(content, content_key_decrypt)
            part_class = FolderPart_Name.objects.get(part_name=part_class)
            part = FolderPart(folder_id=patient.folderinfo, part_class=part_class, part_context=encrypted_content)
            part.save()
            justified = User.objects.get(username=license["justified"])
            justified_key = JustifiedKey(part=part, justified_name=justified, key=encrypted_key)
            justified_key.save()
        json_obj = {'works': 'fined'}
        return JsonResponse(json_obj, status=201)


@csrf_exempt
def create_key(request):
    if request.method == 'POST':
        data = json.loads(request.body)
        license = data[0]
        part_class = data[1]
        key = data[2]
        if not check_license(license):
            return HttpResponse(status=404)
        patient = User.objects.get(username=license["patient"])
        part_class = FolderPart_Name.objects.get(part_name=part_class)
        justified = User.objects.get(username=license["justified"])
        part = FolderPart.objects.get(folder_id=patient.folderinfo, part_class=part_class)
        if not JustifiedKey.objects.filter(part=part, justified_name=justified, key=key).exists():
            justified_key = JustifiedKey(part=part, justified_name=justified, key=key)
            justified_key.save()
        content_response = {"done": 1}
        return JsonResponse(content_response, status=201)


@api_view(['POST'])
@csrf_exempt
@permission_classes([IsAdminUser])
def delete_justified_key(request):
    post_content = json.loads(request.body)
    print(post_content)
    patient = post_content['patient']
    justified = post_content['justified']
    folder_parts_delete_key = post_content['folder_parts']
    old_total_key = post_content['old_total_key']
    new_total_key = post_content['new_total_key']
    old_total_key_decrypt = decrypt(old_total_key)
    new_total_key_decrypt = decrypt(new_total_key)
    patient = User.objects.get(username=patient)
    justified = User.objects.get(username=justified)
    all_folder_parts = FolderPart_Name.objects.all().values_list()
    for part in all_folder_parts:
        folder_part_name_object = FolderPart_Name.objects.get(part_name=part[1])
        folder_part_object = FolderPart.objects.get(part_class=folder_part_name_object,folder_id=patient.folderinfo)
        decrypted_content = decrypt_aes(folder_part_object.part_context, old_total_key_decrypt)
        encrypted_content = encrypt_aes(decrypted_content, new_total_key_decrypt)
        folder_part_object.part_context = encrypted_content
        folder_part_object.save()
    for part in folder_parts_delete_key:
        folder_part_name_object = FolderPart_Name.objects.get(part_name=part)
        folder_part_object = FolderPart.objects.get(folder_id=patient.folderinfo, part_class=folder_part_name_object)
        key = JustifiedKey.objects.filter(part=folder_part_object, justified_name=justified)
        key.delete()
    return Response(status=201)


class UserViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = User.objects.all().order_by('-date_joined')
    serializer_class = UserSerializer
    permission_classes = [permissions.IsAuthenticated]


class GroupViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows groups to be viewed or edited.
    """
    queryset = Group.objects.all()
    serializer_class = GroupSerializer
    permission_classes = [permissions.IsAuthenticated]


class GetFolderPartNames(viewsets.ModelViewSet):
    queryset = FolderPart_Name.objects.all()
    serializer_class = FolderPartNameSerializer
