# coding: utf-8

from django.conf import settings
from django.core.cache import cache
from rest_framework import status
from rest_framework.response import Response

from procu.api import models, tasks
from procu.api.enums import LINK
from procu.api.utils import is_readonly, json_dumps
from procu.rest import generics, pagination
from procu.rest.permissions import EntryPermission
from . import serializers
from .permissions import LinkListPermission
from .utils import fetch_enquiries, fetch_tickets


class LinkListCreate(generics.ListCreateAPIView):
    permission_classes = (LinkListPermission,)
    pagination_class = pagination.NoPagination
    serializer_class = serializers.LinkCreate

    def post_initial(self, request):
        enquiry = self.enquiry = generics.get_object_or_404(
            models.Enquiry.objects.permitted(self.request.user).only(
                'id', 'status'
            ),
            pk=self.kwargs['enquiry_id'],
        )
        self.check_object_permissions(request, enquiry)

    def get_queryset(self):
        return models.Link.objects.filter(
            enquiry=self.kwargs['enquiry_id']
        ).order_by('type', 'created_at')

    def list(self, request, *args, **kwargs):

        # Calculate permission to delete links
        perms = self.enquiry.permissions(request.user)
        can_delete = not is_readonly() and 'api.update_enquiry' in perms

        # ----------------------------------------------------------------------

        links = list(self.get_queryset())

        e_keys = [l.key for l in links if l.type == LINK.PROCU]
        tids = [l.key for l in links if l.type == LINK.TRACKER]

        data = {}
        data.update(fetch_enquiries(request.user, e_keys))

        # ----------------------------------------------------------------------

        tickets = {}

        for tid in tids:
            ticket = cache.get((request.user.id, tid))
            if ticket is not None:
                tickets[tid] = ticket

        new_tickets = fetch_tickets(request, set(tids) - set(tickets))

        for key, ticket in new_tickets.items():
            cache.set((request.user.id, key), ticket, timeout=60 * 5)
            tickets[key] = ticket

        data.update(tickets)

        # ----------------------------------------------------------------------

        results = []

        for link in links:
            obj = {
                'id': link.id,
                'object': {
                    'type': {
                        'key': LINK.keys[link.type],
                        'name': LINK.i18n[link.type],
                    },
                    'data': data.get(link.key, {}),
                    'icon': settings.LINK_FAVICONS[link.type],
                    'url': settings.LINK_URLS[link.type].format(key=link.key),
                },
                'key': link.key,
                'can_delete': can_delete,
            }
            results.append(obj)

        return Response({'results': results})

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        data = serializer.validated_data

        existing = set(self.enquiry.links.values_list('key', flat=True))

        links = []
        tickets = []

        common = {'author': request.user, 'enquiry': self.enquiry}

        for link in data['links']:

            key = link['id']
            key = f'YP{key}' if link['type'] == LINK.PROCU else key

            if key in existing:
                continue

            links.append(models.Link(key=key, type=link['type'], **common))

            if link['type'] == LINK.PROCU:
                # Add reverse link
                links.append(
                    models.Link(
                        key=self.enquiry.key,
                        enquiry_id=link['id'],
                        type=link['type'],
                        author=request.user,
                    )
                )

            if link['type'] == LINK.TRACKER:
                tickets.append(link['id'])

        models.Link.objects.bulk_create(links)

        if tickets:
            tasks.sync_remotes(
                enquiry_id=self.enquiry.id,
                link_to=tickets,
                unlink_from=[],
                request=request,
            )

        if links:
            new = {'keys': [link.key for link in links]}

            models.Log.objects.create(
                enquiry_id=self.enquiry.id,
                user=self.request.user,
                type='create_enquiry_links',
                data=json_dumps(new),
                new=json_dumps(new),
            )

        return Response([link.key for link in links])


class LinkDestroy(generics.DestroyAPIView):
    permission_classes = (EntryPermission,)
    lookup_url_kwarg = 'link_id'

    def get_queryset(self):
        return models.Link.objects.filter(enquiry=self.kwargs['enquiry_id'])

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()

        enquiry_id = self.kwargs['enquiry_id']
        link_type = instance.type
        key = instance.key

        self.perform_destroy(instance)

        if link_type == LINK.TRACKER:
            tasks.sync_remotes(
                enquiry_id=enquiry_id,
                link_to=[],
                unlink_from=[key],
                request=request,
            )

        elif link_type == LINK.PROCU:
            models.Link.objects.filter(
                enquiry__key=key, key=f'YP{enquiry_id}'
            ).delete()

        new = {'keys': [key]}

        models.Log.objects.create(
            enquiry_id=enquiry_id,
            user=self.request.user,
            type='remove_enquiry_links',
            data=json_dumps(new),
            new=json_dumps(new),
        )

        return Response(status=status.HTTP_204_NO_CONTENT)
