from typing import Any

from django.utils.translation import gettext_lazy as _
from rest_framework.exceptions import ValidationError
from rest_framework.fields import (
    BooleanField,
    CharField,
    DictField,
    Field,
    FloatField,
    IntegerField,
    JSONField,
    ListField,
    UUIDField,
)
from rest_framework.serializers import ListSerializer, ModelSerializer, Serializer

from core.models import Address


class AddressAutocompleteInputSerializer(Serializer):  # type: ignore [type-arg]
    q = CharField(required=True)
    limit = IntegerField(required=False, min_value=1, max_value=10, default=5)


class AddressSuggestionSerializer(Serializer):  # type: ignore [type-arg]
    display_name = CharField()
    lat = FloatField()
    lon = FloatField()
    address = DictField(child=CharField())


class AddressSerializer(ModelSerializer):  # type: ignore [type-arg]
    latitude = FloatField(source="location.y", read_only=True)
    longitude = FloatField(source="location.x", read_only=True)

    class Meta:
        model = Address
        fields = [
            "uuid",
            "street",
            "address_line",
            "district",
            "city",
            "region",
            "postal_code",
            "country",
            "latitude",
            "longitude",
            "raw_data",
            "api_response",
            "user",
        ]
        read_only_fields = [
            "latitude",
            "longitude",
            "raw_data",
            "api_response",
        ]


class AddressCreateSerializer(ModelSerializer):  # type: ignore [type-arg]
    raw_data = CharField(
        write_only=True,
        max_length=512,
    )
    address_line_1 = CharField(write_only=True, max_length=128, required=True)
    address_line_2 = CharField(write_only=True, max_length=128, required=False)

    class Meta:
        model = Address
        fields = ["raw_data", "address_line_1", "address_line_2"]

    def create(self, validated_data: dict[str, Any]) -> Address:
        raw = validated_data.pop("raw_data")
        user = None
        if self.context["request"].user.is_authenticated:
            user = self.context["request"].user
        return Address.objects.create(raw_data=raw, user=user, **validated_data)  # type: ignore [no-untyped-call]


class DoFeedbackSerializer(Serializer):  # type: ignore [type-arg]
    comment = CharField(required=True)
    rating = IntegerField(min_value=1, max_value=10, default=10)
    action = CharField(default="add")

    def validate(self, data: dict[str, Any]) -> dict[str, Any]:
        if data["action"] == "add" and not all([data["comment"], data["rating"]]):
            raise ValidationError(_("you must provide a comment, rating, and order product uuid to add feedback."))
        return data


class CacheOperatorSerializer(Serializer):  # type: ignore [type-arg]
    key = CharField(required=True)
    data = JSONField(required=False)  # type: ignore [assignment]
    timeout = IntegerField(required=False)


class ContactUsSerializer(Serializer):  # type: ignore [type-arg]
    email = CharField(required=True)
    name = CharField(required=True)
    subject = CharField(required=True)
    phone_number = CharField(required=False)
    message = CharField(required=True)


class LanguageSerializer(Serializer):  # type: ignore [type-arg]
    code = CharField(required=True)
    name = CharField(required=True)
    flag = CharField()


class RecursiveField(Field):  # type: ignore [type-arg]
    def to_representation(self, value: Any) -> Any:
        parent = self.parent
        if isinstance(parent, ListSerializer):
            parent = parent.parent

        serializer_class = parent.__class__
        return serializer_class(value, context=self.context).data

    def to_internal_value(self, data: Any) -> Any:
        return data


class AddOrderProductSerializer(Serializer):  # type: ignore [type-arg]
    product_uuid = CharField(required=True)
    attributes = ListField(required=False, child=DictField(), default=list)


class BulkAddOrderProductsSerializer(Serializer):  # type: ignore [type-arg]
    products = ListField(child=AddOrderProductSerializer(), required=True)


class RemoveOrderProductSerializer(Serializer):  # type: ignore [type-arg]
    product_uuid = CharField(required=True)
    attributes = JSONField(required=False, default=dict)


class BulkRemoveOrderProductsSerializer(Serializer):  # type: ignore [type-arg]
    products = ListField(child=RemoveOrderProductSerializer(), required=True)


class AddWishlistProductSerializer(Serializer):  # type: ignore [type-arg]
    product_uuid = CharField(required=True)


class RemoveWishlistProductSerializer(Serializer):  # type: ignore [type-arg]
    product_uuid = CharField(required=True)


class BulkAddWishlistProductSerializer(Serializer):  # type: ignore [type-arg]
    product_uuids = ListField(child=CharField(required=True), allow_empty=False, max_length=64)


class BulkRemoveWishlistProductSerializer(Serializer):  # type: ignore [type-arg]
    product_uuids = ListField(child=CharField(required=True), allow_empty=False, max_length=64)


class BuyOrderSerializer(Serializer):  # type: ignore [type-arg]
    force_balance = BooleanField(required=False, default=False)
    force_payment = BooleanField(required=False, default=False)
    promocode_uuid = CharField(required=False)
    shipping_address_uuid = CharField(required=False)
    billing_address_uuid = CharField(required=False)
    chosen_products = AddOrderProductSerializer(many=True, required=False)


class BuyUnregisteredOrderSerializer(Serializer):  # type: ignore [type-arg]
    products = AddOrderProductSerializer(many=True, required=True)
    promocode_uuid = UUIDField(required=False)
    customer_name = CharField(required=True)
    customer_email = CharField(required=True)
    customer_phone_number = CharField(required=True)
    billing_customer_address_uuid = CharField(required=False)
    shipping_customer_address_uuid = CharField(required=False)
    payment_method = CharField(required=True)


class BuyAsBusinessOrderSerializer(Serializer):  # type: ignore [type-arg]
    products = AddOrderProductSerializer(many=True, required=True)
    business_identificator = CharField(required=True)
    promocode_uuid = UUIDField(required=False)
    business_email = CharField(required=True)
    business_phone_number = CharField(required=True)
    billing_business_address_uuid = CharField(required=False)
    shipping_business_address_uuid = CharField(required=False)
    payment_method = CharField(required=True)
