import time
from django.db.models import Q, Min, Max
from django.core.cache import cache
from rest_framework import serializers
from counter.models import DeviceCount, DeviceInfo
from mosquito.models import DeviceInfo as CelexDeviceInfo
from mosquito.models import MosqPostStatistic, DevicePostStatistic


def get_vol(device_id, cur_vol):
    vol_min_key = '{}_vol_min'.format(device_id)
    vol_max_key = '{}_vol_max'.format(device_id)
    vol_min = cache.get(vol_min_key)
    vol_max = cache.get(vol_max_key)
    if not vol_min:
        vol_min = DeviceCount.objects.filter(device_id=device_id).aggregate(vol_min=Min('vol'))['vol_min']
        cache.set(vol_min_key, vol_min, 60 * 5)
    if not vol_max:
        vol_max = DeviceCount.objects.filter(device_id=device_id).aggregate(vol_max=Max('vol'))['vol_max']
        cache.set(vol_max_key, vol_max, 60 * 5)

    vol = 100 * (int(cur_vol) - int(vol_min)) / (int(vol_max) - int(vol_min))
    return '{}{}'.format(round(vol, 1), '%')


def get_latest(device_id):
    latest_key = 'device_latest_{}'.format(device_id)
    latest = cache.get(latest_key)
    if latest:
        return latest
    latest = DeviceCount.objects.filter(device_id=device_id).order_by('-data_time')[0]
    s = DeviceCountBaseSerializer(latest)
    data = s.data
    cache.set(latest_key, data, 60 * 10)
    return data


def get_device(device_id):
    device_key = 'device_lon_{}'.format(device_id)
    device = cache.get(device_key)
    if device:
        return device
    qs = DeviceCount.objects.filter(~Q(longitude=0), device_id=device_id).order_by('-data_time')
    if qs.count() == 0:
        return None
    device = qs.first()
    s = DeviceCountBaseSerializer(device)
    data = s.data
    cache.set(device_key, data, 60 * 10)
    return data


class DeviceCountBaseSerializer(serializers.ModelSerializer):
    class Meta:
        model = DeviceCount
        fields = '__all__'


class DeviceCountSerializer(serializers.ModelSerializer):
    device_name = serializers.SerializerMethodField()
    mosq_count = serializers.SerializerMethodField()
    signal = serializers.SerializerMethodField()
    energy = serializers.SerializerMethodField()
    calc_time = serializers.SerializerMethodField()
    longitude = serializers.SerializerMethodField()
    latitude = serializers.SerializerMethodField()

    class Meta:
        model = DeviceCount
        fields = [
            'id',
            'device_id',
            'device_name',
            'signal',
            'mosq_count',
            'energy',
            'calc_time',
            'longitude',
            'latitude'
        ]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.device = None

    def get_mosq_count(self, obj):
        return obj.count

    def get_signal(self, obj):
        return obj.csq

    def get_energy(self, obj):
        if float(obj.vol) <= 100:
            return '{}{}'.format(round(float(obj.vol), 1), '%')
        return get_vol(obj.device_id, obj.vol)

    def get_calc_time(self, obj):
        return obj.data_time.strftime('%Y-%m-%d %H:%M:%S')

    def get_device_name(self, obj):
        device_id = obj.device_id
        device = cache.get(device_id)
        if device:
            self.device = device
            return device.device_name
        qs = CelexDeviceInfo.objects.filter(device_id=device_id)
        if qs.count() > 0:
            device = qs[0]
            self.device = device
            cache.set(device_id, device, 60 * 60 * 24)
            return device.device_name
        return None

    def get_longitude(self, obj):
        device = self.device
        if device:
            if device.longitude:
                return device.longitude
        return obj.longitude

    def get_latitude(self, obj):
        device = self.device
        if device:
            if device.latitude:
                return device.latitude
        return obj.latitude


class DeviceInfoSerializer(serializers.ModelSerializer):
    device_name = serializers.SerializerMethodField()
    status = serializers.SerializerMethodField()
    count = serializers.SerializerMethodField()
    signal = serializers.SerializerMethodField()
    energy = serializers.SerializerMethodField()
    coordinate = serializers.SerializerMethodField()
    time = serializers.SerializerMethodField()

    class Meta:
        model = DeviceInfo
        fields = [
            'device_id',
            'device_name',
            'status',
            'count',
            'signal',
            'energy',
            'coordinate',
            'time',
        ]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.latest = None
        self.cur_device = None

    def get_device_name(self, obj):
        qs = CelexDeviceInfo.objects.filter(device_id=obj.device_id)
        if qs.count() > 0:
            device = qs[0]
            self.cur_device = device
            return device.device_name
        return None

    def get_status(self, obj):
        return obj.online

    def get_count(self, obj) ->str:
        try:
            # self.latest = DeviceCount.objects.filter(device_id=obj.device_id).order_by('-data_time')[0]
            self.latest = get_latest(obj.device_id)
        except IndexError:
            self.latest = None
        if self.latest:
            return self.latest['count']
        return '0'

    def get_signal(self, obj) ->str:
        if self.latest:
            return self.latest['csq']
        return '0'

    def get_energy(self, obj) ->str:
        if self.latest:
            if float(self.latest['vol']) <= 100:
                return '{}{}'.format(round(float(self.latest['vol']), 1), '%')
            return get_vol(obj.device_id, self.latest['vol'])
        return '0%'

    def get_coordinate(self, obj):
        if self.cur_device:
            lon, lat = [self.cur_device.longitude, self.cur_device.latitude]
            if lon and lat:
                return [lon, lat]

        # query = DeviceCount.objects.filter(~Q(longitude=0), device_id=obj.device_id).order_by('-data_time')
        device = get_device(obj.device_id)
        if device:
            return [device['longitude'], device['latitude']]
        return None

    def get_time(self, obj):
        if self.latest:
            return self.latest['data_time'].replace('T', ' ').replace('Z', '')
        return None


class LatestDailySerializer(serializers.ModelSerializer):

    class Meta:
        model = MosqPostStatistic
        fields = [
            'date',
            'total',
            'increment',
        ]


class DeviceLogHistorySerializer(serializers.ModelSerializer):

    class Meta:
        model = DevicePostStatistic
        fields = [
            'device_id',
            'total',
            'date'
        ]
