from rest_framework import serializers
from review.models import Review, ReviewTextAuthor
from account.models import User
from translation.models import Language
from establishment.models import Establishment
from product.models import Product


class ReviewSerializer(serializers.Serializer):
    vintage = serializers.IntegerField()
    mark = serializers.FloatField(allow_null=True)
    establishment_id = serializers.IntegerField()
    created_at = serializers.DateTimeField(format='%m-%d-%Y %H:%M:%S')
    aasm_state = serializers.CharField(allow_null=True)
    reviewer_id = serializers.IntegerField()
    id = serializers.IntegerField()

    def validate(self, data):
        data.update({
            'reviewer': self.get_reviewer(data),
            'status': Review.READY if data['aasm_state'] == 'published' else Review.TO_INVESTIGATE,
            'published_at': data.pop('created_at'),
            'old_id': data.pop('id'),
            'content_object': self.get_establishment(data),
        })
        data.pop('reviewer_id')
        data.pop('establishment_id')
        data.pop('aasm_state')
        return data

    def create(self, validated_data):
        obj, _ = Review.objects.update_or_create(
            old_id=validated_data['old_id'],
            defaults=validated_data,
        )
        return obj

    @staticmethod
    def get_reviewer(data):
        if data['reviewer_id'] and not data['reviewer_id'] == -1:
            user = User.objects.filter(old_id=data['reviewer_id']).first()
            return user

    @staticmethod
    def get_establishment(data):
        establishment = Establishment.objects.filter(old_id=data['establishment_id']).first()
        if not establishment:
            raise ValueError(f"Establishment not found with old_id {data['establishment_id']}: ")
        return establishment


class ProductReviewSerializer(ReviewSerializer):
    vintage = serializers.IntegerField()
    mark = serializers.FloatField(allow_null=True)
    product_id = serializers.IntegerField()
    created_at = serializers.DateTimeField(format='%m-%d-%Y %H:%M:%S')
    aasm_state = serializers.CharField(allow_null=True)
    reviewer_id = serializers.IntegerField(allow_null=True)
    id = serializers.IntegerField()

    def validate(self, data):
        data.update({
            'reviewer': self.get_reviewer(data),
            'status': Review.READY if data['aasm_state'] == 'published' else Review.TO_INVESTIGATE,
            'published_at': data.pop('created_at'),
            'old_id': data.pop('id'),
            'content_object': self.get_product(data),
        })
        data.pop('reviewer_id')
        data.pop('product_id')
        data.pop('aasm_state')
        data.pop('establishment_id')
        return data

    def create(self, validated_data):
        obj, _ = Review.objects.update_or_create(
            old_id=validated_data['old_id'],
            defaults=validated_data,
        )
        return obj

    @staticmethod
    def get_reviewer(data):
        user = User.objects.filter(old_id=data['reviewer_id']).first()
        if user:
            return user

    @staticmethod
    def get_product(data):
        establishment = Product.objects.filter(old_id=data['product_id']).first()
        if not establishment:
            raise ValueError(f"Product not found with old_id {data['product_id']}: ")
        return establishment


class ReviewTextSerializer(serializers.Serializer):
    review_id = serializers.IntegerField()
    locale = serializers.CharField(allow_null=True)
    text = serializers.CharField()
    updated_by = serializers.IntegerField(allow_null=True)
    created_at = serializers.DateTimeField(format='%m-%d-%Y %H:%M:%S')
    updated_at = serializers.DateTimeField(format='%m-%d-%Y %H:%M:%S')

    def validate(self, data):
        data.update({
            'new_text': self.get_text(data),
            'review': self.get_review(data),
            'author': self.get_author(data),
        })
        data.pop('review_id')
        data.pop('text')
        return data

    def create(self, validated_data):
        review = validated_data['review']
        author_payload = {
            'review': review,
            'author': validated_data['author'],
            'locale': validated_data['locale'] or 'en-GB',
            'created': validated_data['created_at'],
        }
        if review.text:
            review.text.update(validated_data['new_text'])
        else:
            review.text = validated_data['new_text']
        review.save()

        if validated_data['author'] and validated_data['locale']:
            review_author, _ = ReviewTextAuthor.objects.update_or_create(
                review=review,
                locale=author_payload['locale'],
                defaults=author_payload,
            )

        return review

    @staticmethod
    def get_text(data):
        locale = data['locale'] or 'en-GB'
        text = data['text']
        return {locale: text}

    @staticmethod
    def get_review(data):
        review = Review.objects.filter(old_id=data['review_id']).first()
        if not review:
            raise ValueError(f"Review not found with old_id {data['review_id']}: ")
        return review

    @staticmethod
    def get_author(data):
        user = User.objects.filter(old_id=data['updated_by']).first()
        if user:
            return user


class LanguageSerializer(serializers.ModelSerializer):
    LANGUAGES = {
        "be-BE": "Belarusian - Belarusia",
        "el-GR": "Greek - Greek",
        "he-IL": "Israel - Hebrew",
        "hr-HR": "Croatia - Croatian",
        "hu-HU": "Hangarian - Hungary",
        "ja-JP": "Japanese - Japan",
        "ka-GE": "Georgian - Georgia",
        "pl-PL": "Polish - Poland",
        "ro-RO": "Romainian - Romania",
        "ru-RU": "Russian - Russia",
        "sl-SI": "Slovenian - Slovenia",
        "ar-DZ": "Arabic - Algeria",
        "ar-BH": "Arabic - Bahrain",
        "ar-EG": "Arabic - Egypt",
        "ar-IQ": "Arabic - Iraq",
        "ar-JO": "Arabic - Jordan",
        "ar-KW": "Arabic - Kuwait",
        "ar-LB": "Arabic - Lebanon",
        "ar-LY": "Arabic - Libya",
        "ar-MA": "Arabic - Morocco",
        "ar-OM": "Arabic - Oman",
        "ar-QA": "Arabic - Qatar",
        "ar-SA": "Arabic - Saudi Arabia",
        "ar-SY": "Arabic - Syria",
        "ar-TN": "Arabic - Tunisia",
        "ar-AE": "Arabic - United Arab Emirates",
        "ar-YE": "Arabic - Yemen",
        "az-AZ": "Azeri - Cyrillic",
        "zh-CN": "Chinese - China",
        "zh-HK": "Chinese - Hong Kong SAR",
        "zh-MO": "Chinese - Macau SAR",
        "zh-SG": "Chinese - Singapore",
        "zh-TW": "Chinese - Taiwan",
        "nl-BE": "Dutch - Belgium",
        "nl-NL": "Dutch - Netherlands",
        "en-AU": "English - Australia",
        "en-BZ": "English - Belize",
        "en-CA": "English - Canada",
        "en-CB": "English - Caribbean",
        "en-GB": "English - Great Britain",
        "en-IN": "English - India",
        "en-IE": "English - Ireland",
        "en-JM": "English - Jamaica",
        "en-NZ": "English - New Zealand",
        "en-PH": "English - Phillippines",
        "en-ZA": "English - Southern Africa",
        "en-TT": "English - Trinidad",
        "en-US": "English - United States",
        "fr-BE": "French - Belgium",
        "fr-CA": "French - Canada",
        "fr-FR": "French - France",
        "fr-LU": "French - Luxembourg",
        "fr-CH": "French - Switzerland",
        "fr-MA": "French - Morocco",
        "gd-IE": "Gaelic - Ireland",
        "de-AT": "German - Austria",
        "de-DE": "German - Germany",
        "de-LI": "German - Liechtenstein",
        "de-LU": "German - Luxembourg",
        "de-CH": "German - Switzerland",
        "it-IT": "Italian - Italy",
        "it-CH": "Italian - Switzerland",
        "ms-BN": "Malay - Brunei",
        "ms-MY": "Malay - Malaysia",
        "no-NO": "Norwegian - Bokml",
        "pt-BR": "Portuguese - Brazil",
        "pt-PT": "Portuguese - Portugal",
        "ro-MO": "Romanian - Moldova",
        "ru-MO": "Russian - Moldova",
        "sr-SP": "Serbian - Cyrillic",
        "es-AR": "Spanish - Argentina",
        "es-BO": "Spanish - Bolivia",
        "es-CL": "Spanish - Chile",
        "es-CO": "Spanish - Colombia",
        "es-CR": "Spanish - Costa Rica",
        "es-DO": "Spanish - Dominican Republic",
        "es-EC": "Spanish - Ecuador",
        "es-SV": "Spanish - El Salvador",
        "es-GT": "Spanish - Guatemala",
        "es-HN": "Spanish - Honduras",
        "es-MX": "Spanish - Mexico",
        "es-NI": "Spanish - Nicaragua",
        "es-PA": "Spanish - Panama",
        "es-PY": "Spanish - Paraguay",
        "es-PE": "Spanish - Peru",
        "es-PR": "Spanish - Puerto Rico",
        "es-ES": "Spanish - Spain (Traditional)",
        "es-UY": "Spanish - Uruguay",
        "es-VE": "Spanish - Venezuela",
        "sv-FI": "Swedish - Finland",
        "sv-SE": "Swedish - Sweden",
        "uz-UZ": "Uzbek - Cyrillic",
    }

    id = serializers.CharField()
    locale = serializers.CharField()

    class Meta:
        model = Language
        fields = ("locale", "id")

    def validate(self, data):
        data = self.set_old_id(data)
        data = self.set_locale(data)
        return data

    def create(self, validated_data):
        try:
            locale = Language.objects.filter(locale=validated_data['locale']).first()
            if locale is None:
                raise Language.DoesNotExist
            locale.old_id = validated_data['old_id']
            locale.save()
        except Language.DoesNotExist:
            locale = Language.objects.create(**validated_data)

        return locale

    def set_locale(self, data):
        data['locale'] = data['locale'].replace("_", "-")
        try:
            data['title'] = self.LANGUAGES[data['locale']]
        except Exception as e:
            raise ValueError(f"{data}: {e}")
        return data

    def set_old_id(self, data):
        data['old_id'] = data.pop("id")
        return data
