"""News app common serializers."""
from django.shortcuts import get_object_or_404
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from rest_framework.fields import SerializerMethodField

from account.serializers.common import UserBaseSerializer
from gallery.models import Image
from location import models as location_models
from location.serializers import AddressBaseSerializer, CountrySimpleSerializer
from main.models import SiteSettings
from news import models
from rating import models as rating_models
from tag.serializers import TagBaseSerializer
from utils import exceptions as utils_exceptions
from utils.models import get_current_locale, get_default_locale
from utils.serializers import (
    CarouselCreateSerializer, FavoritesCreateSerializer, ImageBaseSerializer, ProjectModelSerializer, TranslatedField,
)


class AgendaSerializer(ProjectModelSerializer):
    start_datetime = serializers.DateTimeField()
    end_datetime = serializers.DateTimeField()
    address = AddressBaseSerializer()
    event_name_translated = TranslatedField()
    content_translated = TranslatedField()

    class Meta:
        """Meta class."""

        model = models.Agenda
        fields = (
            'id',
            'start_datetime',
            'end_datetime',
            'address',
            'content_translated',
            'event_name_translated'
        )


class NewsBannerSerializer(ProjectModelSerializer):
    title_translated = TranslatedField()
    image_url = serializers.URLField()
    content_url = serializers.URLField()

    class Meta:
        """Meta class."""

        model = models.NewsBanner
        fields = (
            'id',
            'title_translated',
            'image_url',
            'content_url'
        )


class NewsTypeSerializer(serializers.ModelSerializer):
    """News type serializer."""

    class Meta:
        """Meta class."""

        model = models.NewsType
        fields = ('id', 'name')


class NewsBaseSerializer(ProjectModelSerializer):
    """Base serializer for News model."""

    title_translated = TranslatedField()
    subtitle_translated = TranslatedField()
    news_type = NewsTypeSerializer(read_only=True)
    tags = TagBaseSerializer(read_only=True, many=True, source='visible_tags')
    in_favorites = serializers.BooleanField(allow_null=True, read_only=True)
    view_counter = serializers.IntegerField(read_only=True)
    slug = serializers.SerializerMethodField(read_only=True, allow_null=True)

    def get_slug(self, obj):
        if obj.slugs:
            return obj.slugs.get(get_current_locale()) \
                   or obj.slugs.get(get_default_locale()) \
                   or next(iter(obj.slugs.values()))

    class Meta:
        """Meta class."""

        model = models.News
        fields = (
            'id',
            'slug',
            'title_translated',
            'subtitle_translated',
            'is_highlighted',
            'news_type',
            'tags',
            'view_counter',
        )


class NewsSimilarListSerializer(NewsBaseSerializer):
    """List serializer for News model."""
    preview_image_url = serializers.URLField()

    class Meta(NewsBaseSerializer.Meta):
        """Meta class."""
        fields = NewsBaseSerializer.Meta.fields + (
            'preview_image_url',
        )


class NewsListSerializer(NewsBaseSerializer):
    """List serializer for News model."""

    image = ImageBaseSerializer(source='crop_main_image', allow_null=True)

    class Meta(NewsBaseSerializer.Meta):
        """Meta class."""

        fields = NewsBaseSerializer.Meta.fields + (
            'image',
            'in_favorites',
        )


class NewsDetailSerializer(NewsBaseSerializer):
    """News detail serializer."""

    description_translated = TranslatedField()
    country = CountrySimpleSerializer(read_only=True)
    author = UserBaseSerializer(source='created_by', read_only=True)
    state_display = serializers.CharField(source='get_state_display', read_only=True)
    gallery = ImageBaseSerializer(read_only=True, source='crop_gallery', many=True)
    start = serializers.DateTimeField(source='publication_datetime', read_only=True)

    class Meta(NewsBaseSerializer.Meta):
        """Meta class."""

        fields = NewsBaseSerializer.Meta.fields + (
            'description_translated',
            'start',
            'end',
            'is_publish',
            'state',
            'state_display',
            'author',
            'country',
            'gallery',
        )


class NewsDetailWebSerializer(NewsDetailSerializer):
    """News detail serializer for web users.."""

    same_theme = SerializerMethodField()
    should_read = SerializerMethodField()
    agenda = AgendaSerializer()
    banner = NewsBannerSerializer()

    class Meta(NewsDetailSerializer.Meta):
        """Meta class."""

        fields = NewsDetailSerializer.Meta.fields + (
            'same_theme',
            'should_read',
            'agenda',
            'banner',
        )

    def get_same_theme(self, obj):
        return NewsSimilarListSerializer(obj.same_theme(self.context['request'].user), many=True, read_only=True).data

    def get_should_read(self, obj):
        return NewsSimilarListSerializer(obj.should_read(self.context['request'].user), many=True, read_only=True).data


class NewsBackOfficeBaseSerializer(NewsBaseSerializer):
    """News back office base serializer."""
    is_published = serializers.BooleanField(source='is_publish', read_only=True)
    descriptions = serializers.ListField(required=False)

    class Meta(NewsBaseSerializer.Meta):
        """Meta class."""

        fields = NewsBaseSerializer.Meta.fields + (
            'title',
            'backoffice_title',
            'subtitle',
            'slugs',
            'locale_to_description_is_active',
            'is_published',
            'duplication_date',
            'must_of_the_week',
            'publication_date',
            'publication_time',
            'created',
            'modified',
            'descriptions',
        )
        extra_kwargs = {
            'created': {'read_only': True},
            'modified': {'read_only': True},
            'duplication_date': {'read_only': True},
            'locale_to_description_is_active': {'allow_null': False},
            'must_of_the_week': {'read_only': True},
        }

    def validate(self, attrs):
        """Overridden validate method."""
        if 'descriptions' in attrs:
            descriptions = attrs.pop('descriptions')
            locales = list(map(lambda x: x['locale'], descriptions))
            status_to_bool = {
                'active': True,
                'inactive': False,
            }
            attrs['slugs'] = {obj['locale']: obj['slug'] for obj in descriptions if 'slug' in obj}
            attrs['title'] = {obj['locale']: obj['title'] for obj in descriptions if 'title' in obj}
            attrs['locale_to_description_is_active'] = {
                obj['locale']: status_to_bool[obj['status']] for obj in descriptions
            }
            attrs['description'] = {obj['locale']: obj['text'] for obj in descriptions if 'text' in obj}
            if self.context['request'].method == 'PATCH':
                instance = models.News.objects.get(pk=self.context['request'].data['id'])
                for key in ['slugs', 'title', 'locale_to_description_is_active', 'description']:
                    for locale in locales:
                        if not attrs[key].get(locale):
                            attrs[key][locale] = getattr(instance, key).get(locale)
        return attrs

    def create(self, validated_data):
        slugs = validated_data.get('slugs')

        if slugs:
            if models.News.objects.filter(
                    slugs__values__contains=list(slugs.values())
            ).exists():
                raise serializers.ValidationError({'slugs': _('News with this slug already exists.')})

        request = self.context.get("request")
        if request and hasattr(request, "user"):
            user = request.user
            validated_data['created_by'] = user

        return super().create(validated_data)

    def update(self, instance, validated_data):
        slugs = validated_data.get('slugs')
        if slugs:
            if models.News.objects.filter(
                    slugs__values__contains=list(slugs.values())
            ).exclude(pk=instance.pk).exists():
                raise serializers.ValidationError({'slugs': _('News with this slug already exists.')})
        return super().update(instance, validated_data)


class NewsBackOfficeDuplicationInfoSerializer(serializers.ModelSerializer):
    """Duplication info for news detail."""

    country = CountrySimpleSerializer(read_only=True)

    class Meta:
        model = models.News
        fields = (
            'id',
            'duplication_date',
            'country',
        )


class NewsBackOfficeDetailSerializer(NewsBackOfficeBaseSerializer,
                                     NewsDetailSerializer):
    """News detail serializer for back-office users."""

    news_type_id = serializers.PrimaryKeyRelatedField(
        source='news_type', write_only=True,
        queryset=models.NewsType.objects.all())
    country_id = serializers.PrimaryKeyRelatedField(
        source='country', write_only=True,
        queryset=location_models.Country.objects.all())
    site_id = serializers.PrimaryKeyRelatedField(
        source='site', write_only=True,
        queryset=SiteSettings.objects.all())
    template_display = serializers.CharField(source='get_template_display',
                                             read_only=True)
    duplicates = NewsBackOfficeDuplicationInfoSerializer(many=True, allow_null=True, read_only=True)

    class Meta(NewsBackOfficeBaseSerializer.Meta, NewsDetailSerializer.Meta):
        """Meta class."""

        fields = NewsBackOfficeBaseSerializer.Meta.fields + \
                 NewsDetailSerializer.Meta.fields + (
                     'description',
                     'news_type_id',
                     'country_id',
                     'site_id',
                     'template',
                     'template_display',
                     'is_international',
                     'duplicates',
                 )


class NewsBackOfficeGallerySerializer(serializers.ModelSerializer):
    """Serializer class for model NewsGallery."""

    class Meta:
        """Meta class"""

        model = models.NewsGallery
        fields = [
            'id',
            'is_main',
        ]

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

    def create(self, validated_data):
        news_pk = self.request_kwargs.get('pk')
        image_id = self.request_kwargs.get('image_id')
        qs = models.NewsGallery.objects.filter(image_id=image_id, news_id=news_pk)
        instance = qs.first()
        if instance:
            qs.update(**validated_data)
            return instance
        return super().create(validated_data)

    def validate(self, attrs):
        """Override validate method."""
        news_pk = self.request_kwargs.get('pk')
        image_id = self.request_kwargs.get('image_id')

        news_qs = models.News.objects.filter(pk=news_pk)
        image_qs = Image.objects.filter(id=image_id)

        if not news_qs.exists():
            raise serializers.ValidationError({'detail': _('News not found')})
        if not image_qs.exists():
            raise serializers.ValidationError({'detail': _('Image not found')})

        news = news_qs.first()
        image = image_qs.first()

        # if image in news.gallery.all():
        #     raise serializers.ValidationError({'detail': _('Image is already added.')})

        attrs['news'] = news
        attrs['image'] = image

        return attrs


class NewsFavoritesCreateSerializer(FavoritesCreateSerializer):
    """Serializer to favorite object w/ model News."""

    def validate(self, attrs):
        """Overridden validate method"""
        # Check establishment object
        news_qs = models.News.objects.filter(slugs__values__contains=[self.slug])

        # Check establishment obj by slug from lookup_kwarg
        if not news_qs.exists():
            raise serializers.ValidationError({'detail': _('Object not found.')})
        else:
            news = news_qs.first()

        # Check existence in favorites
        if news.favorites.filter(user=self.user).exists():
            raise utils_exceptions.FavoritesError()

        attrs['news'] = news
        return attrs

    def create(self, validated_data, *args, **kwargs):
        """Overridden create method"""
        validated_data.update({
            'user': self.user,
            'content_object': validated_data.pop('news')
        })
        return super().create(validated_data)


class NewsCarouselCreateSerializer(CarouselCreateSerializer):
    """Serializer to carousel object w/ model News."""

    def validate(self, attrs):
        news = models.News.objects.filter(pk=self.pk).first()
        if not news:
            raise serializers.ValidationError({'detail': _('Object not found.')})

        if news.carousels.exists():
            raise utils_exceptions.CarouselError()

        attrs['news'] = news
        return attrs

    def create(self, validated_data, *args, **kwargs):
        validated_data.update({
            'country': validated_data['news'].country
        })
        validated_data.update({
            'content_object': validated_data.pop('news'),
            'is_parse': True,
            'active': True,
        })
        return super().create(validated_data)


class NewsCloneCreateSerializer(NewsBackOfficeBaseSerializer,
                                NewsDetailSerializer):
    """Serializer for creating news clone."""
    template_display = serializers.CharField(source='get_template_display',
                                             read_only=True)
    duplicates = NewsBackOfficeDuplicationInfoSerializer(many=True, allow_null=True, read_only=True)

    class Meta(NewsBackOfficeBaseSerializer.Meta, NewsDetailSerializer.Meta):
        fields = NewsBackOfficeBaseSerializer.Meta.fields + NewsDetailSerializer.Meta.fields + (
            'template_display',
            'duplicates',
        )
        read_only_fields = fields

    def create(self, validated_data):
        kwargs = self.context.get('request').parser_context.get('kwargs')
        instance = get_object_or_404(models.News, pk=kwargs['pk'])
        new_country = get_object_or_404(location_models.Country, code=kwargs['country_code'])
        view_count_model = rating_models.ViewCount.objects.create(count=0)
        instance.create_duplicate(new_country, view_count_model)
        return get_object_or_404(models.News, pk=kwargs['pk'])
