from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from rest_framework.validators import UniqueValidator

from verify_trusted.companies.history_types import HistoryType, HistoryTypeSymbol
from verify_trusted.reviews.models import Platform, ReviewSource
from verify_trusted.utils.serializers import (
    AverageRatingRep,
    DynamicFieldsModelSerializer,
    ReviewsCountRep,
)

ABLE_TO_SYNC_NAMES = [
    'Checkatrade',
    'Trustpilot.com',
    'Yelp',
    'HomeAdvisor',
    'Angi',
    'BBB',
    'Google', 'Facebook'
]


class PlatformSerializer(DynamicFieldsModelSerializer):
    able_to_sync_reviews = serializers.SerializerMethodField()
    display_order = serializers.CharField(
        required=False, allow_null=True, allow_blank=True
    )

    class Meta:
        model = Platform
        fields = '__all__'
        extra_kwargs = {
            'name': {
                'allow_blank': False,
                'required': True,
                'validators': [UniqueValidator(queryset=Platform.objects.all())],
            },
            'sync_status': {'default': ReviewSource.SyncStatus.NOT_SYNC},
        }

    def update(self, instance: Platform, validated_data):
        if 'display_order' in validated_data and validated_data['display_order'] == -1:
            validated_data['display_order'] = None
        return super().update(instance, validated_data)

    def create(self, validated_data):
        if 'display_order' in validated_data and validated_data['display_order'] == -1:
            validated_data['display_order'] = None
        return super().create(validated_data)

    def get_able_to_sync_reviews(self, obj: Platform):  # noqa
        return obj.name in ABLE_TO_SYNC_NAMES

    def validate_display_order(self, value):
        if not value or len(value) == 0:
            return -1
        try:
            return int(value)
        except ValueError:
            raise serializers.ValidationError('You must supply an integer')


class UserPlatformCreateSerializer(serializers.ModelSerializer):
    status = serializers.HiddenField(default=Platform.Status.UNAVAILABLE)
    is_popular = serializers.HiddenField(default=False)
    display_order = serializers.HiddenField(default=None)

    class Meta:
        model = Platform
        fields = '__all__'


class ReviewSourceSerializer(
    ReviewsCountRep,
    AverageRatingRep,
    serializers.ModelSerializer,
):
    platform = PlatformSerializer(read_only=True)
    able_to_sync_reviews = serializers.SerializerMethodField()
    sync_status = serializers.CharField(default=ReviewSource.SyncStatus.NOT_SYNC)

    class Meta:
        model = ReviewSource
        fields = '__all__'

    def get_able_to_sync_reviews(self, obj: ReviewSource):  # noqa
        return obj.platform.name in ABLE_TO_SYNC_NAMES


class UserReviewSourcePlatformCreateSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=50)
    url = serializers.CharField(required=True)
    status = serializers.HiddenField(default=Platform.Status.UNAVAILABLE)


class UserReviewSourceCreateSerializer(serializers.ModelSerializer):
    platform = UserReviewSourcePlatformCreateSerializer()

    class Meta:
        model = ReviewSource
        fields = '__all__'
        extra_kwargs = {
            'url': {
                'allow_blank': False,
                'required': True,
            },
            'reviews_count': {
                'default': 0,
            },
            'average_rating': {
                'default': 0,
            },
        }

    def create(self, validated_data):
        platform_data = validated_data['platform']
        platform_url = platform_data['url']
        platform_name = platform_data['name']
        '''
        Checking if platform exists
        '''
        platform = Platform.objects.filter(url=platform_url).first()
        if platform:
            condition = platform.status in [Platform.Status.ACTIVE, Platform.Status.HIDE_REVIEWS]
            if not condition:
                raise ValidationError({'platform': 'This platform is not active yet!'})
            if ReviewSource.objects.filter(
                platform=platform, company=validated_data['company']
            ).exists():
                raise ValidationError(
                    {'platform': 'The review source for this platform already existed!'}
                )
        else:
            if Platform.objects.filter(name=platform_name).exists():
                raise ValidationError(
                    {'platform': 'This platform name already existed!'}
                )
            '''
            Creating new platform with status UNAVAILABLE
            '''
            platform = Platform.objects.create(**platform_data)
        validated_data['platform'] = platform
        return super().create(validated_data)

    def to_representation(self, instance):
        if isinstance(instance, Platform):
            return PlatformSerializer(instance).data
        return super().to_representation(instance)


class ReviewSourceHistorySerializer(serializers.ModelSerializer):
    history_id = serializers.ReadOnlyField()
    history_date = serializers.DateTimeField(read_only=True)
    history_type = serializers.SerializerMethodField()
    platform = PlatformSerializer()

    class Meta:
        model = ReviewSource
        fields = '__all__'

    def get_history_type(self, obj):  # noqa
        history_type = obj.history_type
        if history_type == HistoryTypeSymbol.CREATED:
            return HistoryType.CREATED
        if history_type == HistoryTypeSymbol.CHANGED:
            return HistoryType.CHANGED
        if history_type == HistoryTypeSymbol.DELETED:
            return HistoryType.DELETED
        return history_type
