from django.shortcuts import get_object_or_404
from rest_framework import serializers
from rest_framework_recursive.fields import RecursiveField

from collection import models
from review.serializers import ReviewBaseSerializer
from establishment.serializers import EstablishmentGuideElementSerializer
from location import models as location_models
from main.serializers import SiteShortSerializer
from product.serializers import ProductGuideElementSerializer
from utils import exceptions
from utils.serializers import TranslatedField


class CollectionBaseSerializer(serializers.ModelSerializer):
    """Collection base serializer"""
    name_translated = TranslatedField()
    description_translated = TranslatedField()

    class Meta:
        model = models.Collection
        fields = [
            'id',
            'name_translated',
            'description_translated',
            'image_url',
            'slug',
        ]


class CollectionSerializer(CollectionBaseSerializer):
    """Collection serializer"""
    # COMMON
    block_size = serializers.JSONField()
    is_publish = serializers.BooleanField()
    on_top = serializers.BooleanField()
    slug = serializers.SlugField(allow_blank=False, required=True, max_length=50)

    # REQUEST
    start = serializers.DateTimeField(write_only=True)
    end = serializers.DateTimeField(write_only=True)
    country = serializers.PrimaryKeyRelatedField(
        queryset=location_models.Country.objects.all(),
        write_only=True)

    class Meta(CollectionBaseSerializer.Meta):
        fields = CollectionBaseSerializer.Meta.fields + [
            'start',
            'end',
            'is_publish',
            'on_top',
            'country',
            'block_size',
        ]


class GuideFilterBaseSerializer(serializers.ModelSerializer):
    """GuideFilter serializer"""

    class Meta:
        """Meta class."""
        model = models.GuideFilter
        fields = [
            'id',
            'establishment_type_json',
            'country_json',
            'region_json',
            'sub_region_json',
            'wine_region_json',
            'with_mark',
            'locale_json',
            'max_mark',
            'min_mark',
            'review_vintage_json',
            'review_state_json',
            'guide',
        ]
        extra_kwargs = {
            'guide': {'write_only': True, 'required': False},
            'max_mark': {'required': True},
            'min_mark': {'required': True},
        }

    @property
    def request_kwargs(self):
        """Get url kwargs from request."""
        return self.context.get('request').parser_context.get('kwargs')

    def create(self, validated_data):
        """Overridden create method."""
        guide = get_object_or_404(models.Guide.objects.all(),
                                  pk=self.request_kwargs.get('pk'))
        validated_data['guide'] = guide
        guide_filter = super().create(validated_data)
        guide.generate_elements()
        return guide_filter


class GuideBaseSerializer(serializers.ModelSerializer):
    """Guide serializer"""
    state_display = serializers.CharField(source='get_state_display',
                                          read_only=True)
    guide_type_display = serializers.CharField(read_only=True)
    site_detail = SiteShortSerializer(read_only=True,
                                      source='site')
    guide_filters = GuideFilterBaseSerializer(read_only=True,
                                              source='guidefilter')
    # counters
    restaurant_counter = serializers.IntegerField(read_only=True)
    shop_counter = serializers.IntegerField(read_only=True)
    wine_counter = serializers.IntegerField(read_only=True)
    count_objects_during_init = serializers.IntegerField(read_only=True,
                                                         source='count_related_objects')

    class Meta:
        model = models.Guide
        fields = [
            'id',
            'name',
            'start',
            'end',
            'vintage',
            'slug',
            'guide_type',
            'guide_type_display',
            'site',
            'site_detail',
            'state',
            'state_display',
            'guide_filters',
            'restaurant_counter',
            'shop_counter',
            'wine_counter',
            'count_objects_during_init',
        ]
        extra_kwargs = {
            'guide_type': {'write_only': True},
            'site': {'write_only': True},
            'state': {'write_only': True},
            'start': {'required': True},
            'slug': {'required': False},
            'count_objects_during_init': {'read_only': True},
            'vintage': {'required': True},
        }


class GuideElementBaseSerializer(serializers.ModelSerializer):
    """Serializer for model GuideElement."""
    establishment_detail = EstablishmentGuideElementSerializer(read_only=True,
                                                               source='establishment')
    section_name = serializers.CharField(source='section.name',
                                         allow_null=True)
    wine_color_section_name = serializers.CharField(source='wine_color_section.name',
                                                    allow_null=True)
    node_name = serializers.CharField(source='guide_element_type.name')
    label_photo = serializers.ImageField(source='label_photo.image', allow_null=True)
    city_name = serializers.CharField(source='city.name', allow_null=True)
    product_detail = ProductGuideElementSerializer(read_only=True, source='product')

    children = RecursiveField(required=False, many=True, source='get_children')

    class Meta:
        """Meta class."""
        model = models.GuideElement
        fields = [
            'id',
            'node_name',
            'establishment_detail',
            'review',
            'wine_region',
            'product_detail',
            'priority',
            'city_name',
            'section_name',
            'wine_color_section_name',
            'children',
            'label_photo',
        ]


class AdvertorialBaseSerializer(serializers.ModelSerializer):
    """Serializer for model Advertorial."""

    class Meta:
        """Meta class."""
        model = models.Advertorial
        fields = [
            'number_of_pages',
            'right_pages',
            'guide_element',
        ]
        extra_kwargs = {
            'guide_element': {'required': False}
        }

    @property
    def request_kwargs(self):
        return self.context.get('request').parser_context.get('kwargs')

    def validate(self, attrs):
        # check existence in guide
        guide = get_object_or_404(models.Guide.objects.all(),
                                  pk=self.request_kwargs.get('pk'))
        root_node = models.GuideElement.objects.get_root_node(guide)
        guide_element_qs = root_node.get_descendants().filter(pk=self.request_kwargs.get('element_pk'))
        guide_element = guide_element_qs.first()

        if not guide_element_qs.exists():
            raise exceptions.GuideElementError()

        if models.Advertorial.objects.filter(guide_element=guide_element).exists():
            raise exceptions.AdvertorialError()

        attrs['guide_element'] = guide_element
        return attrs


class GuideElementExportSerializer(GuideElementBaseSerializer):
    """GuideElement export serializer."""
    # establishment = EstablishmentGuideElementSerializer(read_only=True,)
    name = serializers.CharField(source='establishment.name', default=None)
    public_mark = serializers.CharField(source='establishment.public_mark_display', default=None)
    toque_number = serializers.IntegerField(source='establishment.toque_number', default=None)
    schedule = serializers.DictField(source='establishment.schedule_display',
                                     default=None)
    address = serializers.CharField(source='establishment.address.full_address',
                                    default=None)
    phones = serializers.ListField(source='establishment.contact_phones',
                                   default=None)
    establishment_type = serializers.CharField(source='establishment.establishment_type.label',
                                               default=None)
    establishment_subtypes = serializers.ListField(source='establishment.establishment_subtype_labels',
                                                   default=None)
    review = serializers.DictField(source='establishment.last_published_review_data',
                                   default=None)
    price_level = serializers.CharField(source='establishment.price_level_display',
                                        default=None)
    metadata = serializers.ListField(source='establishment.metadata',
                                     default=None)
    advertorial_page = serializers.IntegerField(default=None)

    class Meta:
        model = models.GuideElement
        fields = [
            'id',
            'guide',
            'node_name',
            # 'establishment',
            # 'review',
            # 'wine_region',
            # 'product_detail',
            # 'priority',
            'city_name',
            # 'section_name',
            # 'wine_color_section_name',
            # 'children',
            # 'label_photo',
            'name',
            'public_mark',
            'toque_number',
            'schedule',
            'address',
            'phones',
            'establishment_type',
            'establishment_subtypes',
            'review',
            'price_level',
            'metadata',
            'advertorial_page',
        ]
