import time
from typing import Optional
from django.db.models import Q, Min, Max
from rest_framework import serializers
from django.core.cache import cache
from mosquito.models import Mosquito, MosqPost, DeviceTempLog, WeatherLog, WeatherStationInfo, DeviceInfo
from smart.api.serializers import SmartPushListSerializer


class MosqListSerializer(serializers.ModelSerializer):

    class Meta:
        model = Mosquito
        fields = [
            'name',
            'device_id',
            'region'
        ]


class MosqPostListSerializer(serializers.ModelSerializer):
    smart_push = SmartPushListSerializer(read_only=True)
    region = serializers.SerializerMethodField()

    class Meta:
        model = MosqPost
        fields = [
            'id',
            'mosq',
            'led',
            'energy',
            'region',
            'smart_push',
            'time',
        ]

    def get_region(self, obj):
        return obj.mosq.region


class DeviceTempLogSerializer(serializers.ModelSerializer):
    last_time = serializers.SerializerMethodField()
    create_time = serializers.SerializerMethodField()

    class Meta:
        model = DeviceTempLog
        fields = ['device_id', 'temperature', 'humidity', 'last_time', 'create_time']

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

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


class DeviceSourceException(Exception):
    """
    source should be counter | mosquito
    """


class WeatherLogBaseSerializer(serializers.ModelSerializer):
    class Meta:
        model = WeatherLog
        fields = '__all__'


class WeatherStationInfoBaseSerializer(serializers.ModelSerializer):
    class Meta:
        model = WeatherStationInfo
        fields = '__all__'


device_source_map = {
    'counter': WeatherLogBaseSerializer,
    'mosquito': WeatherStationInfoBaseSerializer,
}


def get_device(device_id: str, source: str) -> Optional[dict]:
    """
    Get device data serialized by DeviceCountBaseSerializer (counter) or DeviceInfoBaseSerializer (mosquito),
    For source 'counter', we get device from device_counter table not device_info, because
    the [lon, lat] info is located in device_counter.
    For source 'mosquito', we get device from mosquito/DeviceInfo model,
    due to the [point_x, point_y] is what we want.

    params: device_id,
    params: source, counter | mosquito
    return: dict
    """
    device_key = 'device_lon_{}'.format(device_id)
    device = cache.get(device_key)
    if device:
        return device

    if source == 'counter':
        qs = WeatherLog.objects.filter(~Q(longitude=0),
                                        device_id=device_id).order_by('-data_time')
    elif source == 'mosquito':
        qs = WeatherStationInfo.objects.filter(device_id=device_id)
    else:
        raise DeviceSourceException("source should be counter or mosquito")

    if qs.count() == 0:
        return None

    device = qs.first()
    s = device_source_map[source](device)
    data = s.data
    cache.set(device_key, data, 60 * 10)
    print(data)
    return data


class WeatherLogSerializer(serializers.ModelSerializer):
    power = serializers.SerializerMethodField()
    device_name = serializers.SerializerMethodField()
    data_time = serializers.SerializerMethodField()
    create_time = serializers.SerializerMethodField()

    class Meta:
        model = WeatherLog
        fields = [
            'data_time',
            'device_id',
            'device_name',
            'env_temp',
            'temperature1', 'temperature2', 'temperature3', 'temperature4', 'temperature5', 'dew_point_temp',
            'env_humi', 'soil_humi1', 'soil_humi2', 'soil_humi3',
            'co2', 'evaporation', 'air_pressure',
            'total_radiation_1_ins', 'scat_radiation_ins', 'direct_radiation_ins', 'total_radiation_2_ins',
            'net_radiation_ins', 'pho_radiation_ins', 'uv_radiation_ins',
            'wind_direction', 'wind_speed_ins', 'wind_speed_2mins', 'wind_speed_10mins',
            'rainfall_interval_cum', 'sunshine_time_interval_cum', 'total_radiation_1_interval_cum',
            'scat_radiation_interval_cum', 'direct_radiation_interval_cum', 'total_radiation_2_interval_cum',
            'net_radiation_interval_cum', 'pho_radiation_interval_cum', 'uv_radiation_interval_cum',
            'rainfall_daily_cum', 'sunshine_time_daily_cum', 'total_radiation_1_daily_cum',
            'scat_radiation_daily_cum', 'direct_radiation_daily_cum', 'total_radiation_2_daily_cum',
            'net_radiation_daily_cum', 'pho_radiation_daily_cum', 'uv_radiation_daily_cum',
            'light_intensity',
            'power',
            'pm25',
            'create_time',
        ]

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

    def get_power(self, obj):
        # power max 12.6V, min 8.5V
        power = int((float(obj.power) - 8.5) / 4.1 * 100)
        return str(power)

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

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

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


class WeatherLogWithInfoSerializer(WeatherLogSerializer):
    longitude = serializers.SerializerMethodField()
    latitude = serializers.SerializerMethodField()
    location_id = serializers.SerializerMethodField()
    weather_code = serializers.SerializerMethodField()
    point_x = serializers.SerializerMethodField()
    point_y = serializers.SerializerMethodField()

    class Meta:
        model = WeatherLog
        fields = [
            'data_time',
            'device_id',
            'device_name',
            'env_temp',
            'temperature1', 'temperature2', 'temperature3', 'temperature4', 'temperature5', 'dew_point_temp',
            'env_humi', 'soil_humi1', 'soil_humi2', 'soil_humi3',
            'co2', 'evaporation', 'air_pressure',
            'total_radiation_1_ins', 'scat_radiation_ins', 'direct_radiation_ins', 'total_radiation_2_ins',
            'net_radiation_ins', 'pho_radiation_ins', 'uv_radiation_ins',
            'wind_direction', 'wind_speed_ins', 'wind_speed_2mins', 'wind_speed_10mins',
            'rainfall_interval_cum', 'sunshine_time_interval_cum', 'total_radiation_1_interval_cum',
            'scat_radiation_interval_cum', 'direct_radiation_interval_cum', 'total_radiation_2_interval_cum',
            'net_radiation_interval_cum', 'pho_radiation_interval_cum', 'uv_radiation_interval_cum',
            'rainfall_daily_cum', 'sunshine_time_daily_cum', 'total_radiation_1_daily_cum',
            'scat_radiation_daily_cum', 'direct_radiation_daily_cum', 'total_radiation_2_daily_cum',
            'net_radiation_daily_cum', 'pho_radiation_daily_cum', 'uv_radiation_daily_cum',
            'light_intensity',
            'power',
            'pm25',
            'create_time',
            'longitude',
            'latitude',
            'location_id',
            'weather_code',
            'point_x',
            'point_y',
        ]

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

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

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

    def get_location_id(self, obj):
        device = self.device
        if device:
            if device.location_id:
                return device.location_id
        return None

    def get_weather_code(self, obj):
        device = self.device
        if device:
            if device.weather_code:
                return device.weather_code
        return None

    def get_point_x(self, obj):
        device = self.device
        if device:
            if device.point_x:
                return device.point_x
        return None

    def get_point_y(self, obj):
        device = self.device
        if device:
            if device.point_y:
                return device.point_y
        return None


class WeatherStationInfoSerializer(serializers.ModelSerializer):

    class Meta:
        model = WeatherStationInfo
        fields = [
            'device_id',
            'device_name',
            'longitude',
            'latitude',
            'location_id',
            'point_x',
            'point_y',
        ]


class DeviceInfoSerializer(serializers.ModelSerializer):

    class Meta:
        model = DeviceInfo
        fields = [
            'weather_code',
            'device_id',
            'device_name',
            'longitude',
            'latitude',
            'weather_device_id',
            'location_id',
            'point_x',
            'point_y',
        ]

