from __future__ import annotations

import json
from collections.abc import Mapping
from typing import TYPE_CHECKING, Any, TypeVar, cast

from attrs import define as _attrs_define
from attrs import field as _attrs_field

from .. import types
from ..types import UNSET, Unset

if TYPE_CHECKING:
    from ..models.shopping_list import ShoppingList
    from ..models.supermarket_category_relation import SupermarketCategoryRelation


T = TypeVar("T", bound="PatchedSupermarket")


@_attrs_define
class PatchedSupermarket:
    """Moves `UniqueValidator`'s from the validation stage to the save stage.
    It solves the problem with nested validation for unique fields on update.

    If you want more details, you can read related issues and articles:
    https://github.com/beda-software/drf-writable-nested/issues/1
    http://www.django-rest-framework.org/api-guide/validators/#updating-nested-serializers

    Example of usage:
    ```
        class Child(models.Model):
        field = models.CharField(unique=True)


    class Parent(models.Model):
        child = models.ForeignKey('Child')


    class ChildSerializer(UniqueFieldsMixin, serializers.ModelSerializer):
        class Meta:
            model = Child


    class ParentSerializer(NestedUpdateMixin, serializers.ModelSerializer):
        child = ChildSerializer()

        class Meta:
            model = Parent
    ```

    Note: `UniqueFieldsMixin` must be applied only on the serializer
    which has unique fields.

    Note: When you are using both mixins
    (`UniqueFieldsMixin` and `NestedCreateMixin` or `NestedUpdateMixin`)
    you should put `UniqueFieldsMixin` ahead.

        Attributes:
            id (int | Unset):
            name (str | Unset):
            description (None | str | Unset):
            shopping_lists (list[ShoppingList] | Unset):
            category_to_supermarket (list[SupermarketCategoryRelation] | Unset):
            open_data_slug (None | str | Unset):
    """

    id: int | Unset = UNSET
    name: str | Unset = UNSET
    description: None | str | Unset = UNSET
    shopping_lists: list[ShoppingList] | Unset = UNSET
    category_to_supermarket: list[SupermarketCategoryRelation] | Unset = UNSET
    open_data_slug: None | str | Unset = UNSET
    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> dict[str, Any]:
        id = self.id

        name = self.name

        description: None | str | Unset
        if isinstance(self.description, Unset):
            description = UNSET
        else:
            description = self.description

        shopping_lists: list[dict[str, Any]] | Unset = UNSET
        if not isinstance(self.shopping_lists, Unset):
            shopping_lists = []
            for shopping_lists_item_data in self.shopping_lists:
                shopping_lists_item = shopping_lists_item_data.to_dict()
                shopping_lists.append(shopping_lists_item)

        category_to_supermarket: list[dict[str, Any]] | Unset = UNSET
        if not isinstance(self.category_to_supermarket, Unset):
            category_to_supermarket = []
            for category_to_supermarket_item_data in self.category_to_supermarket:
                category_to_supermarket_item = category_to_supermarket_item_data.to_dict()
                category_to_supermarket.append(category_to_supermarket_item)

        open_data_slug: None | str | Unset
        if isinstance(self.open_data_slug, Unset):
            open_data_slug = UNSET
        else:
            open_data_slug = self.open_data_slug

        field_dict: dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update({})
        if id is not UNSET:
            field_dict["id"] = id
        if name is not UNSET:
            field_dict["name"] = name
        if description is not UNSET:
            field_dict["description"] = description
        if shopping_lists is not UNSET:
            field_dict["shopping_lists"] = shopping_lists
        if category_to_supermarket is not UNSET:
            field_dict["category_to_supermarket"] = category_to_supermarket
        if open_data_slug is not UNSET:
            field_dict["open_data_slug"] = open_data_slug

        return field_dict

    def to_multipart(self) -> types.RequestFiles:
        files: types.RequestFiles = []

        if not isinstance(self.id, Unset):
            files.append(("id", (None, str(self.id).encode(), "text/plain")))

        if not isinstance(self.name, Unset):
            files.append(("name", (None, str(self.name).encode(), "text/plain")))

        if not isinstance(self.description, Unset):
            if isinstance(self.description, str):
                files.append(("description", (None, str(self.description).encode(), "text/plain")))
            else:
                files.append(("description", (None, str(self.description).encode(), "text/plain")))

        if not isinstance(self.shopping_lists, Unset):
            for shopping_lists_item_element in self.shopping_lists:
                files.append(
                    (
                        "shopping_lists",
                        (None, json.dumps(shopping_lists_item_element.to_dict()).encode(), "application/json"),
                    )
                )

        if not isinstance(self.category_to_supermarket, Unset):
            for category_to_supermarket_item_element in self.category_to_supermarket:
                files.append(
                    (
                        "category_to_supermarket",
                        (None, json.dumps(category_to_supermarket_item_element.to_dict()).encode(), "application/json"),
                    )
                )

        if not isinstance(self.open_data_slug, Unset):
            if isinstance(self.open_data_slug, str):
                files.append(("open_data_slug", (None, str(self.open_data_slug).encode(), "text/plain")))
            else:
                files.append(("open_data_slug", (None, str(self.open_data_slug).encode(), "text/plain")))

        for prop_name, prop in self.additional_properties.items():
            files.append((prop_name, (None, str(prop).encode(), "text/plain")))

        return files

    @classmethod
    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
        from ..models.shopping_list import ShoppingList
        from ..models.supermarket_category_relation import SupermarketCategoryRelation

        d = dict(src_dict)
        id = d.pop("id", UNSET)

        name = d.pop("name", UNSET)

        def _parse_description(data: object) -> None | str | Unset:
            if data is None:
                return data
            if isinstance(data, Unset):
                return data
            return cast(None | str | Unset, data)

        description = _parse_description(d.pop("description", UNSET))

        _shopping_lists = d.pop("shopping_lists", UNSET)
        shopping_lists: list[ShoppingList] | Unset = UNSET
        if _shopping_lists is not UNSET:
            shopping_lists = []
            for shopping_lists_item_data in _shopping_lists:
                shopping_lists_item = ShoppingList.from_dict(shopping_lists_item_data)

                shopping_lists.append(shopping_lists_item)

        _category_to_supermarket = d.pop("category_to_supermarket", UNSET)
        category_to_supermarket: list[SupermarketCategoryRelation] | Unset = UNSET
        if _category_to_supermarket is not UNSET:
            category_to_supermarket = []
            for category_to_supermarket_item_data in _category_to_supermarket:
                category_to_supermarket_item = SupermarketCategoryRelation.from_dict(category_to_supermarket_item_data)

                category_to_supermarket.append(category_to_supermarket_item)

        def _parse_open_data_slug(data: object) -> None | str | Unset:
            if data is None:
                return data
            if isinstance(data, Unset):
                return data
            return cast(None | str | Unset, data)

        open_data_slug = _parse_open_data_slug(d.pop("open_data_slug", UNSET))

        patched_supermarket = cls(
            id=id,
            name=name,
            description=description,
            shopping_lists=shopping_lists,
            category_to_supermarket=category_to_supermarket,
            open_data_slug=open_data_slug,
        )

        patched_supermarket.additional_properties = d
        return patched_supermarket

    @property
    def additional_keys(self) -> list[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties
