# coding: utf-8

from itertools import groupby

from django.core import mail
from django.db.models import Case, F, When
from django.template.loader import get_template
from django.utils.encoding import force_text
from rest_framework.response import Response

from procu.api import enums, models
from procu.api.common.comment import create_quote_comment
from procu.api.push import external as push
from procu.api.utils import dict_diff, json_dumps, strtobool
from procu.rest import generics
from . import permissions, serializers

DECLINE = get_template('quote_decline_comment.txt')
CHECKOUT = get_template('quote_checkout_comment.txt')


class RequestCheckout(generics.GenericAPIView):
    serializer_class = serializers.EnquiryCheckoutSerializer
    permission_classes = (permissions.CheckoutPermission,)
    lookup_field = 'enquiry_id'
    lookup_url_kwarg = 'enquiry_id'

    def get_queryset(self):
        return models.Request.objects.permitted(self.request.user)

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

        dry_run = strtobool(request.GET.get('dryrun', '0'), default=True)

        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        data = serializer.validated_data

        rfx = self.object
        user = request.user

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

        products = (
            models.QuoteProduct.objects.values('id', 'qty', 'quote_id')
            .annotate(
                name=Case(
                    When(is_replacement=False, then=F('enquiry_product__name')),
                    default=F('name'),
                )
            )
            .filter(quote__request=rfx, id__in=data['products'])
            .order_by('quote_id', 'id')
        )

        quotes = list(
            models.Quote.objects.filter(request=rfx).values(
                'id',
                'status',
                'reason',
                'has_offer',
                title=F('supplier__title'),
            )
        )

        groups = {
            quote_id: list(group)
            for quote_id, group in groupby(
                products, lambda x: x.pop('quote_id')
            )
        }

        for quote in quotes:
            quote['products'] = groups.get(quote['id'], [])

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

        result = {
            'checkout': [],
            'declined': [],
            'ignored': [],
            'summary': data['summary'],
        }

        messages = []

        for quote in quotes:

            message = None

            if quote['products']:
                message = CHECKOUT.render({'products': quote['products']})
                result['checkout'].append(quote)
                extra = {
                    'status': enums.QS.CHECKOUT,
                    'reason': enums.QR.NONE,
                    'has_won': True,
                }

            elif quote['has_offer']:

                message = DECLINE.render()
                result['declined'].append(quote)
                extra = {'status': enums.QS.CLOSED, 'reason': enums.QR.DECLINED}

            else:
                result['ignored'].append(quote)
                extra = {'status': enums.QS.CLOSED, 'reason': enums.QR.IGNORED}

            if dry_run:
                continue

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

            models.Quote.objects.filter(id=quote['id']).update(**extra)

            old = {
                'status': force_text(enums.QS.i18n[quote['status']]),
                'reason': force_text(enums.QR.i18n[quote['reason']]),
            }

            new = {
                'status': force_text(enums.QS.i18n[extra['status']]),
                'reason': force_text(enums.QR.i18n[extra['reason']]),
            }

            diff = dict_diff(old, new, show_unchanged=False)

            if diff:
                models.Log.objects.create(
                    enquiry_id=rfx.enquiry_id,
                    quote_id=quote['id'],
                    user=user,
                    type='update_quote',
                    data=json_dumps(diff),
                )

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

            if message is not None:
                create_quote_comment(
                    quote_id=quote['id'],
                    user=user,
                    data={'message': message},
                    notify_from=(),
                )

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

            if quote['products']:
                # Win
                msgs = push.notify_quote_checkout(
                    quote['id'], user, quote['products']
                )
                messages.extend(msgs)

            elif quote['has_offer']:
                # Lose
                msgs = push.notify_quote_declined(quote['id'], user)
                messages.extend(msgs)

            else:
                # Ignore
                if diff:
                    msgs = push.notify_quote_updated(quote['id'], user, diff)
                    messages.extend(msgs)

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

        rfx.summary = data['summary']
        rfx.save(update_fields=('summary',))

        with mail.get_connection(fail_silently=True) as conn:
            conn.send_messages(messages)

        return Response({'result': result})
