# coding: utf-8
from __future__ import unicode_literals, absolute_import

from datetime import timedelta

from django.core.serializers.json import Serializer as JsonSerializer
from django.utils import timezone

from emission.core.storage import BaseStorage


class Serializer(JsonSerializer):
    def handle_fk_field(self, obj, field):
        self._current[field.name] = field.value_from_object(obj)

    def handle_m2m_field(self, obj, field):
        pass


class OrmStorage(BaseStorage):

    id_field = 'id'

    def __init__(self, transaction_wait_delta):
        self.transaction_wait_delta = transaction_wait_delta

    def get_queryset(self):
        raise NotImplementedError

    def get_filtered_qs(self):
        qs = self.get_queryset()
        if self.transaction_wait_delta:
            date = timezone.now().replace(tzinfo=None)
            date -= timedelta(seconds=self.transaction_wait_delta)
            qs = qs.filter(creation_time__lt=str(date))
        return qs

    @property
    def values_args(self):
        return self.id_field, 'data', 'action', 'creation_time'

    # Далее догруженные методы.

    def cut(self, date):
        self.get_queryset().filter(creation_time__lt=date).delete()

    def append(self, data, action):
        self.insert(msg_id=None, data=data, action=action)

    def insert(self, msg_id, data, action):
        # TODO Надо учитват время, когда вставляется в середину.
        entry, created = self.get_queryset().get_or_create(
            defaults={'data': data, 'action': action},
            **{self.id_field: msg_id}
        )

        if not created:
            entry.data = data
            entry.save()

        return entry

    def get_one(self, msg_id):
        return (
            self.get_queryset()
            .values(*self.values_args)
            .get(**{self.id_field: msg_id})
        )

    def get_last_id(self):
        return (
            self.get_filtered_qs()
            .values_list(self.id_field, flat=True)
            .order_by('-' + self.id_field)
            .first()
        )

    def get_next_id(self, current_id):
        return (
            self.get_filtered_qs()
            .filter(**{'{}__gt'.format(self.id_field): current_id})
            .values_list(self.id_field, flat=True)
            .order_by(self.id_field)
            .first()
        )

    def get_slice(self, start, stop=None, max_rows=None):
        qs = (
            self.get_filtered_qs()
            .values(*self.values_args)
            .filter(**{self.id_field + '__gte': start})
            .order_by(self.id_field)
        )

        if stop is not None:
            qs = qs.filter(**{self.id_field + '__lte': stop})
        if max_rows:
            qs = qs[:max_rows]
        return qs.iterator()

    def delete_one(self, msg_id):
        self.get_queryset().get(**{self.id_field: msg_id}).delete()

    def serialize_objects(self, objs):
        return Serializer().serialize(objs)
