# -*- coding: utf-8 -*-
import logging
from collections import defaultdict

from django.db import models
from picklefield.fields import PickledObjectField

BULK_SIZE = 100


class BulkSqliteQuerySet(models.query.QuerySet):
    def iter_bulk(self, **filters):
        '''  '''
        if len(filters) > 1:
            raise Exception(u'only one filter expression allowed')
        
        if filters:
            BULK_SIZE = 100
            key, values = filters.popitem()
            for i in range(0, len(values), BULK_SIZE):
                for obj in self.filter(**{key: values[i:i+BULK_SIZE]}):
                    yield obj
        else:
            BULK_SIZE = 200
            for i in range(0, self.count(), BULK_SIZE):
                for obj in self[i:i+BULK_SIZE]:
                    yield obj
            

class BulkSqliteManager(models.Manager):
    use_for_related_fields = True
    def get_query_set(self):
        return BulkSqliteQuerySet(self.model)
    
    def iter_bulk(self, **kwargs):
        return self.get_query_set().iter_bulk(**kwargs)
    
    
class BaseModel(models.Model):
    class Meta:
        abstract = True
        
    objects = BulkSqliteManager()
    
        
class GroupBase(BaseModel):
    class Meta:
        abstract = True
        
    name = models.TextField() 
    code = models.CharField(max_length = 10, unique=True)
     
    to_download = models.IntegerField(default = 0)
    waiting = models.IntegerField(u'Ожидается', default = 0)
    downloaded = models.IntegerField(u'Скачано', default = 0)
    ordered = models.IntegerField(u'Заказано', default = 0)
    downloadable = models.IntegerField(u'Готово', default = 0)
    
    channel_count_err = models.IntegerField(default = 0)
    length_err = models.IntegerField(default = 0)
    mismatch_data_err = models.IntegerField(default = 0)
    no_link_err = models.IntegerField(default = 0)
    
    stat_attrs = 'channel_count_err length_err mismatch_data_err no_link_err waiting downloaded to_download'.split()
    
    @staticmethod
    def get_stats(orders):
        stats = dict([(attr, 0) for attr in GroupBase.stat_attrs], downloadable=0)
        for o in orders:
            if isinstance(o, Order):
                o = o.__dict__
            for attr in GroupBase.stat_attrs:
                if o.get(attr):
                    stats[attr] += 1
            if o['waiting'] == False and o['no_link_err'] == False:
                stats['downloadable'] += 1
        stats['ordered'] = len(orders)
        return stats
        
    
class Region(GroupBase):
    class Meta:
        ordering = ['name']
        
    @staticmethod
    def update_stats(*pks):
        for region_pk in pks:
            logging.info(u'Обновляется статистика региона %s', Region.objects.get(pk = region_pk))
            orders = Order.objects.filter(uik__region_id = region_pk).values(*GroupBase.stat_attrs)
            stats = GroupBase.get_stats(orders)
            Region.objects.filter(pk = region_pk).update(**stats)
            
    def __unicode__(self):
        return self.name


class UIK(GroupBase):
    num = models.IntegerField(u'Номер', null = True)
    region = models.ForeignKey('Region')
    
    tmin = models.DateTimeField(null = True)
    tmax = models.DateTimeField(null = True)
    
    @staticmethod
    def update_stats(*pks):
        regions = set()
        for uik in UIK.objects.select_related('region').prefetch_related('orders').iter_bulk(pk__in = pks):
            logging.info(u'Обновляется статистика %s', uik)
            regions.add(uik.region_id)
            stats = GroupBase.get_stats(uik.orders.all())
            tmins, tmaxs = zip(*[(o.tstart, o.tend) for o in uik.orders.all()])
            stats['tmin'] = min(tmins) if tmins else None
            stats['tmax'] = max(tmaxs) if tmaxs else None
            UIK.objects.filter(pk = uik.pk).update(**stats)
        
        Region.update_stats(*regions)

    def __unicode__(self):
        return u'{uik.region.name} УИК №{uik.num}'.format(uik=self)


class Order(BaseModel):
    uik = models.ForeignKey('UIK', related_name = 'orders')
    orderid = models.CharField(max_length = 20, unique = True, db_index = True)
    orderstatus = models.CharField(max_length = 50, null = True)
    
    created = models.DateTimeField(null = True)
    #created = models.DateTimeField()
    
    tstart = models.DateTimeField(null = True)
    tend = models.DateTimeField(null = True)
    
    to_download = models.BooleanField(default = True)
    waiting = models.BooleanField(default = True)
    downloaded = models.BooleanField(default = False)
    unavailable = models.BooleanField(default = False)
    
    channel_count_err = models.BooleanField(default = False)
    length_err = models.BooleanField(default = False)
    mismatch_data_err = models.BooleanField(default = False)
    no_link_err = models.BooleanField(default = False) # empty archive links
    
    archive_data = PickledObjectField(null = True)
    archive_urls = PickledObjectField(null = True)

    def __unicode__(self):
        self.hstart = self.tstart.strftime('%H:%M') if self.tstart else '?'
        return u'{o.orderid} ({o.uik.region.name} УИК №{o.uik.num} {o.hstart})'.format(o=self)
        
