# -*- coding: utf-8 -*-
'''
Created on Jul 01, 2014

@author: tc
'''
from datetime import datetime
import json
import logging
import uuid

from django.db import transaction
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
from django.http import Http404
from django.http.response import HttpResponse, HttpResponseBadRequest
from django.shortcuts import get_object_or_404, redirect
from django.utils import dateparse
from django.views.generic import View
from django.conf import settings

from renkanmanager.models import Renkan, Revision, Workspace
from renkanmanager.serializers import RenkanSerializer, RevisionSerializer, WorkspaceSerializer
from renkanmanager.utils import parse_bool

from rest_framework import permissions, status
from rest_framework.response import Response
from rest_framework.views import APIView

logger = logging.getLogger(__name__)

class RenkanList(APIView):
    """
        View for listing renkans or posting new renkan
    """

    queryset = Renkan.objects.select_related('current_revision')

    def get(self, request, workspace_guid='', format=None):
        if workspace_guid == '':
            renkans = self.queryset.all()
        else:
            renkans = self.queryset.filter(workspace__workspace_guid=workspace_guid)
        serializer = RenkanSerializer(renkans, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK, content_type='application/json')

    def post(self, request, workspace_guid='', format=None):
        create_data = {key:request.data[key] for key in request.data.keys()}

        source_renkan_guid_str = request.GET.get("source_renkan_id", request.data.get("source_renkan_id", None))
        source_revision_guid_str = request.GET.get("source_revision_id", request.data.get("source_revision_id", None))
        try:
            source_renkan_guid =  source_renkan_guid_str and uuid.UUID(source_renkan_guid_str) or None
            source_revision_guid = source_revision_guid_str and uuid.UUID(source_revision_guid_str) or None
        except ValueError:
            return Response({'detail': 'Source renkan guid %s or source revision guid %s not correctly formatted'%(source_revision_guid_str, source_revision_guid_str)}, status=status.HTTP_400_BAD_REQUEST)

        source_revision = None
        if source_renkan_guid is not None:
            try:
                source_renkan=Renkan.objects.select_related('current_revision').get(renkan_guid=source_renkan_guid)
            except Renkan.DoesNotExist:
                return Response({'detail': 'Source renkan %s does not exist'%source_renkan_guid}, status=status.HTTP_404_NOT_FOUND)
            source_revision = source_renkan.current_revision
        elif source_revision_guid is not None:
            try:
                source_revision=Revision.objects.get(revision_guid=source_revision_guid)
            except Revision.DoesNotExist:
                return Response({'detail': 'Source revision %s does not exist'%source_revision_guid}, status=status.HTTP_404_NOT_FOUND)

        if source_revision:
            create_data["source_revision_id"] = source_revision.revision_guid
            create_data["title"] = request.data.get("title", source_revision.title)
            create_data["content"] = source_revision.content

        try:
            workspace_guid_uuid =  workspace_guid and uuid.UUID(workspace_guid) or None
        except ValueError:
            return Response({'detail': 'workspace guid %r not correctly formatted'%workspace_guid}, status=status.HTTP_400_BAD_REQUEST)

        if workspace_guid_uuid:
            try:
                workspace = Workspace.objects.get(workspace_guid=workspace_guid_uuid)
            except Workspace.DoesNotExist:
                return Response({'detail': 'Workspace '+workspace_guid+' does not exist'}, status=status.HTTP_404_NOT_FOUND)
            create_data["workspace_id"] = workspace_guid
        serializer = RenkanSerializer(data=create_data)
        if serializer.is_valid():
            creator = request.user if request.user and not request.user.is_anonymous() else None
            serializer.save(creator=creator)
            return Response(serializer.data, status=status.HTTP_201_CREATED, content_type='application/json')
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class RenkanDetail(APIView):
    """
        View for retrieving, updating or deleting a single renkan
    """
    lookup_field = "renkan_guid"
    queryset = Renkan.objects.select_related('current_revision')

    def get_object(self, renkan_guid):
        try:
            renkan_uuid = uuid.UUID(renkan_guid)
        except:
            raise ValueError('renkan guid %r bad format'%renkan_guid)
        return self.queryset.get(renkan_guid=renkan_uuid)

    def dispatch(self, *args, **kwargs):
        return super(RenkanDetail, self).dispatch(*args, **kwargs)

    def get(self, request, renkan_guid, format=None):
        try:
            renkan = self.get_object(renkan_guid=renkan_guid)
        except ValueError:
            return Response({'detail': 'Renkan project %r guid badly formatted'%renkan_guid}, status=status.HTTP_400_BAD_REQUEST)
        except Renkan.DoesNotExist:
            return Response({'detail': 'Renkan project %r does not exist'%renkan_guid}, status=status.HTTP_404_NOT_FOUND)

        self.check_object_permissions(request, renkan)
        serializer = RenkanSerializer(renkan)
        if parse_bool(request.GET.get("content_only", "false")):
            return Response(json.loads(serializer.data["content"]), status=status.HTTP_200_OK, content_type='application/json')
        return Response(serializer.data, status=status.HTTP_200_OK, content_type='application/json')

    def put(self, request, renkan_guid, format=None):
        try:
            renkan = self.get_object(renkan_guid=renkan_guid)
        except ValueError:
            return Response({'detail': 'Renkan project %r guid badly formatted'%renkan_guid}, status=status.HTTP_400_BAD_REQUEST)
        except Renkan.DoesNotExist:
            return Response({'detail': 'Renkan project %r does not exist'%renkan_guid}, status=status.HTTP_404_NOT_FOUND)
        logger.debug("RENKAN PUT %r : CHECKING OBJECT PERMISSION", renkan_guid)
        logger.debug("RENKAN PUT: permission? %r", request.user.has_perm("change_renkan", renkan))
        self.check_object_permissions(request, renkan)
        logger.debug("RENKAN PUT: PERMISSION GRANTED")
        if parse_bool(request.GET.get("content_only", "false")):
            put_data = {}
            put_data["content"] = json.dumps(request.data)
            put_data["title"] = request.data.get("title", "")
        else:
            put_data = request.data
        validation_timestamp = request.GET.get("validation_timestamp")
        if validation_timestamp is None and put_data.get("content") is not None:
            validation_timestamp =  json.loads(put_data["content"]).get("updated", "")
        if validation_timestamp:
            validation_timestamp =  dateparse.parse_datetime(validation_timestamp)
        create_new_revision = parse_bool(request.GET.get('create_new_revision', 'false'))
        serializer = RenkanSerializer(renkan, data=put_data, validation_timestamp=validation_timestamp)
        if serializer.is_valid():
            serializer.save(updator=request.user, create_new_revision=create_new_revision)
            if parse_bool(request.GET.get("content_only", "false")):
                return Response(json.loads(serializer.data["content"]), status=status.HTTP_200_OK, content_type='application/json')
            return Response(serializer.data, status=status.HTTP_200_OK, content_type='application/json')
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @transaction.atomic
    def delete(self, request, renkan_guid, format=None):
        try:
            to_delete_renkan = self.get_object(renkan_guid=renkan_guid)
        except ValueError:
            return Response({'detail': 'Renkan project %r guid badly formatted'%renkan_guid}, status=status.HTTP_400_BAD_REQUEST)
        except Renkan.DoesNotExist:
            return Response({'detail': 'Renkan project %r does not exist'%renkan_guid}, status=status.HTTP_404_NOT_FOUND)
        self.check_object_permissions(request, to_delete_renkan)
        to_delete_renkan.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

class WorkspaceList(APIView):
    """
        View for listing workspaces or creating new workspace
    """

    queryset = Workspace.objects

    def get(self, request, format=None):
        workspaces = self.queryset.all()
        serializer = WorkspaceSerializer(workspaces, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = WorkspaceSerializer(data=request.data)
        if serializer.is_valid():
            creator = request.user if request.user and not request.user.is_anonymous() else None
            serializer.save(creator=creator)
            return Response(serializer.data, status=status.HTTP_201_CREATED, content_type='application/json')
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class WorkspaceDetail(APIView):
    """
        View for retrieving, updating or deleting a single workspace
    """

    lookup_field = "workspace_guid"
    queryset = Workspace.objects

    def get_object(self, workspace_guid):
        try:
            workspace_uuid = uuid.UUID(workspace_guid)
        except:
            raise ValueError('workspace guid %r bad format'%workspace_guid)

        return self.queryset.get(workspace_guid=workspace_uuid)

    def get(self, request, workspace_guid, format=None):
        try:
            workspace = self.get_object(workspace_guid=workspace_guid)
        except ValueError:
            return Response({'detail': 'Workspace %r guid badly formatted'%workspace_guid}, status=status.HTTP_400_BAD_REQUEST)
        except Workspace.DoesNotExist:
            return Response({'detail': 'Workspace %r does not exist.'%workspace_guid}, status=status.HTTP_404_NOT_FOUND)


        self.check_object_permissions(request, workspace)
        serializer = WorkspaceSerializer(workspace)
        return Response(serializer.data, status=status.HTTP_200_OK, content_type='application/json')

    def put(self, request, workspace_guid, format=None):
        try:
            workspace = self.get_object(workspace_guid=workspace_guid)
        except ValueError:
            return Response({'detail': 'Workspace %r guid badly formatted'%workspace_guid}, status=status.HTTP_400_BAD_REQUEST)
        except Workspace.DoesNotExist:
            return Response({'detail': 'Workspace %r does not exist.'%workspace_guid}, status=status.HTTP_404_NOT_FOUND)

        self.check_object_permissions(request, workspace)
        serializer = WorkspaceSerializer(workspace, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK, content_type='application/json')
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, workspace_guid, format=None):
        try:
            to_delete_workspace = self.get_object(workspace_guid=workspace_guid)
        except ValueError:
            return Response({'detail': 'Workspace %r guid badly formatted'%workspace_guid}, status=status.HTTP_400_BAD_REQUEST)
        except Workspace.DoesNotExist:
            return Response({'detail': 'Workspace %r does not exist.'%workspace_guid}, status=status.HTTP_404_NOT_FOUND)

        self.check_object_permissions(request, to_delete_workspace)
        if to_delete_workspace.renkan_count != 0:
            return Response({'detail': 'Workspace '+workspace_guid+' cannot be deleted because it is not empty'}, status=status.HTTP_400_BAD_REQUEST)
        to_delete_workspace.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

class RevisionList(APIView):
    """
        View for listing revisions from a given renkan
    """

    def get_queryset(self, renkan_guid=""):
        if renkan_guid:
            return Revision.objects.filter(parent_renkan__renkan_guid=renkan_guid)
        else:
            return Revision.objects

    def get(self, request, renkan_guid, format=None):
        revisions = self.get_queryset(renkan_guid)
        if not revisions:
            return Response({'detail': 'Renkan project '+renkan_guid+' does not exist'}, status=status.HTTP_404_NOT_FOUND)
        serializer = RevisionSerializer(revisions.all(), many=True)
        return Response(serializer.data, status=status.HTTP_200_OK, content_type='application/json')

class RevisionDetail(APIView):
    """
        View for retrieving or deleting a single revision from a given renkan
    """

    lookup_field = "revision_guid"

    def get_queryset(self, renkan_guid=""):
        try:
            renkan_uuid = renkan_guid and uuid.UUID(renkan_guid)
        except:
            raise ValueError("renkan guid %r not correctly formatted"%renkan_guid)


    def get_revision(self, renkan_guid, revision_guid):
        try:
            renkan_uuid = renkan_guid and uuid.UUID(renkan_guid)
        except:
            raise ValueError('Renkan project %r guid bad format'%renkan_guid)
        try:
            revision_uuid = revision_guid and uuid.UUID(revision_guid)
        except:
            raise ValueError('Revision %r guid bad format'%revision_guid)

        revisions = None
        if renkan_uuid:
            revisions = Revision.objects.filter(parent_renkan__renkan_guid=renkan_uuid)
        else:
            revisions = Revision.objects
        if not revisions:
            raise ObjectDoesNotExist('Renkan project %r does not exist'%renkan_guid)
        try:
            revision = revisions.get(revision_guid=revision_uuid)
        except Revision.DoesNotExist:
            raise ObjectDoesNotExist('Revision %r does not exist'%revision_guid)
        return revisions, revision

    def get(self, request, renkan_guid, revision_guid, format=None):

        try:
            _, revision = self.get_revision(renkan_guid, revision_guid)
        except ValueError as e:
            return Response({'detail': e.args[0]}, status=status.HTTP_400_BAD_REQUEST)
        except ObjectDoesNotExist as e:
            return Response({'detail': e.args[0]}, status=status.HTTP_404_NOT_FOUND)

        self.check_object_permissions(request, revision)
        serializer = RevisionSerializer(revision)
        return Response(serializer.data, status=status.HTTP_200_OK, content_type='application/json')

    def delete(self, request, renkan_guid, revision_guid, format=None):
        try:
            revisions, revision = self.get_revision(renkan_guid, revision_guid)
        except ValueError as e:
            return Response({'detail': e.args[0]}, status=status.HTTP_400_BAD_REQUEST)
        except ObjectDoesNotExist as e:
            return Response({'detail': e.args[0]}, status=status.HTTP_404_NOT_FOUND)

        self.check_object_permissions(request, revision)
        if revisions.count() == 1:
            return Response({'detail': 'You cannot delete the last remaining revision of a renkan from the Revision API. Try deleting the parent Renkan with the Renkan API'}, status=status.HTTP_400_BAD_REQUEST)
        if revision.is_current_revision:
            return Response({'detail': 'You cannot delete the current revision of a renkan from the Revision API.'}, status=status.HTTP_400_BAD_REQUEST)
        revision.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)
