from dateutil.relativedelta import relativedelta
from django import forms
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
from sform import FieldsetField
from rest_framework import serializers


class SafeWikiFormattedField(serializers.ReadOnlyField):

    def bind(self, field_name, parent):
        self.source = 'get_safe_' + field_name
        super().bind(field_name, parent)


class NonStrictFieldsetField(FieldsetField):

    def clean(self, new_value, old_value, required, trim_on_empty, base_initial, base_data):
        """
        Почти тупо скопирован базовый метод. Иначе никак.
        Отличается от базового тем, что если поле не обязательное
        но есть ошибки в инкапсулированной форме, то в качестве значения возвращаем None
        """
        if new_value and not isinstance(new_value, dict):
            raise ValidationError(
                'Value should be a dict',
                code='should_be_a_dict',
            )
        if required and not new_value:
            raise ValidationError('This field is required.', code='required')

        if trim_on_empty and not new_value:
            raise ValidationError('Avoid writing to cleaned_data ', code='empty_value')

        sform = self.sform_cls(
            data=new_value,
            initial=old_value,
            base_initial=base_initial,
            base_data=base_data,
        )
        errors = sform._get_errors()
        if errors:
            if required:
                raise ValidationError(errors)
            else:
                return None
        return sform.cleaned_data


class RelativeDeltaField(forms.Field):

    default_error_messages = {
        'invalid': _('Enter a valid duration.'),
    }

    def prepare_value(self, value):
        from intranet.femida.src.core.db.fields import format_relative_delta

        if isinstance(value, relativedelta):
            return format_relative_delta(value)
        return value

    def to_python(self, value):
        from intranet.femida.src.core.db.fields import parse_relative_delta

        if value in self.empty_values:
            return None
        if isinstance(value, relativedelta):
            return value
        parsed = parse_relative_delta(str(value))
        if parsed is None:
            raise ValidationError(self.error_messages['invalid'], code='invalid')
        return parsed
