import datetime
import logging

from django.forms.utils import to_current_timezone
from django.utils.formats import get_format
from django.utils.translation import gettext_lazy
from rest_framework import serializers, ISO_8601
from rest_framework.serializers import *

from core.models import ConsoleAuthSettings, TLSSettings

_log = logging.getLogger(__name__)


class AuthSettingsSerializer(serializers.ModelSerializer):
    class Meta:
        model = ConsoleAuthSettings
        fields = ('login_attempts_limit', 'login_block_timeout')


class TLSSettingsSerializer(serializers.ModelSerializer):
    class Meta:
        model = TLSSettings
        fields = ["enabled", "certificate", "key"]
        extra_kwargs = {
            'enabled': {
                'required': True
            }
        }

    def validate(self, attrs):
        file_count = 0
        if attrs.get("certificate", None):
            file_count += 1
        if attrs.get("key", None):
            file_count += 1
        _log.info(f"File count: {file_count}")

        attrs['file_count'] = file_count

        if attrs['enabled'] and file_count == 0 and (not self.instance.certificate.name or
                                                     not self.instance.key.name):
            _log.error("No cert or key provided from model")
            raise ValidationError(gettext_lazy("No certificate or key provided"))

        if file_count == 1:
            _log.error("No cert or key provided from request")
            raise ValidationError(gettext_lazy("No certificate or key provided"))

        return attrs

    def to_representation(self, tls_settings: TLSSettings) -> OrderedDict:
        data = super(TLSSettingsSerializer, self).to_representation(tls_settings)
        if tls_settings.certificate:
            data['certificate'] = tls_settings.certificate.url
        if tls_settings.key:
            data['key'] = tls_settings.key.url
        return data


class DateTimeLocalizedField(serializers.DateTimeField):
    def __init__(self, format=empty, input_formats=None, default_timezone=None, *args, unix=False, **kwargs):
        if unix:
            format, input_formats = '%s', ['%s']
        else:
            if format is empty:
                format = get_format('DATETIME_INPUT_FORMATS')[0]
            if input_formats is None:
                input_formats = get_format('DATETIME_INPUT_FORMATS')
                input_formats.append(ISO_8601)  # any locale support iso-8601
        super().__init__(format, input_formats, default_timezone, *args, **kwargs)


class DateLocalizedField(serializers.DateField):
    def __init__(self, format=empty, input_formats=None, *args, unix=False, **kwargs):
        if unix:
            format, input_formats = '%s', ['%s']
        else:
            if format is empty:
                format = get_format('DATE_INPUT_FORMATS')[0]
            if input_formats is None:
                input_formats = get_format('DATE_INPUT_FORMATS')
                input_formats.append(ISO_8601)  # any locale support iso-8601
        super().__init__(format, input_formats, *args, **kwargs)


class TimeLocalizedField(serializers.TimeField):
    def __init__(self, format=empty, input_formats=None, *args, **kwargs):
        if format is empty:
            format = '%H:%M'
        if input_formats is None:
            input_formats = get_format('TIME_INPUT_FORMATS')
            input_formats.append(ISO_8601)  # any locale support iso-8601
        super().__init__(format, input_formats, *args, **kwargs)


class TimeLocalizedTzAwareField(TimeLocalizedField):
    @staticmethod
    def _replace_time(datetime_obj, time_obj):
        return datetime_obj.replace(hour=time_obj.hour, minute=time_obj.minute, second=time_obj.second,
                                    microsecond=time_obj.microsecond)

    def to_internal_value(self, value):
        t_tz_naive = super().to_internal_value(value)
        if isinstance(t_tz_naive, datetime.time):
            dt_tz_aware = TimeLocalizedTzAwareField._replace_time(timezone.localtime(), t_tz_naive)
            t_utc_naive = dt_tz_aware.astimezone().time()
            value = t_utc_naive
        return value

    def to_representation(self, value):
        t_utc_naive = value
        if isinstance(t_utc_naive, datetime.time):
            dt_utc_aware = TimeLocalizedTzAwareField._replace_time(timezone.now(), t_utc_naive)
            t_tz_naive = to_current_timezone(dt_utc_aware).time()
            value = t_tz_naive
        return super().to_representation(value)


class ModelLocalizedSerializer(serializers.ModelSerializer):
    serializer_field_mapping = serializers.ModelSerializer.serializer_field_mapping.copy()
    serializer_field_mapping[models.DateField] = DateLocalizedField
    serializer_field_mapping[models.DateTimeField] = DateTimeLocalizedField
    serializer_field_mapping[models.TimeField] = TimeLocalizedTzAwareField
