from __future__ import annotations

import datetime
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 dateutil.parser import isoparse

from ..models.booking_type_enum import BookingTypeEnum
from ..types import UNSET, Unset

if TYPE_CHECKING:
    from ..models.inventory_entry import InventoryEntry
    from ..models.inventory_location import InventoryLocation


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


@_attrs_define
class InventoryLog:
    """
    Attributes:
        entry (InventoryEntry): Adds nested create feature
        old_inventory_location (InventoryLocation): 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.
        new_inventory_location (InventoryLocation): 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.
        created_at (datetime.datetime):
        id (int | Unset):
        booking_type (BookingTypeEnum | Unset): * `add` - Add
            * `remove` - Remove
            * `move` - Move
        old_amount (float | Unset):
        new_amount (float | Unset):
        note (None | str | Unset):
    """

    entry: InventoryEntry
    old_inventory_location: InventoryLocation
    new_inventory_location: InventoryLocation
    created_at: datetime.datetime
    id: int | Unset = UNSET
    booking_type: BookingTypeEnum | Unset = UNSET
    old_amount: float | Unset = UNSET
    new_amount: float | Unset = UNSET
    note: None | str | Unset = UNSET
    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)

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

        old_inventory_location = self.old_inventory_location.to_dict()

        new_inventory_location = self.new_inventory_location.to_dict()

        created_at = self.created_at.isoformat()

        id = self.id

        booking_type: str | Unset = UNSET
        if not isinstance(self.booking_type, Unset):
            booking_type = self.booking_type.value

        old_amount = self.old_amount

        new_amount = self.new_amount

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

        field_dict: dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update(
            {
                "entry": entry,
                "old_inventory_location": old_inventory_location,
                "new_inventory_location": new_inventory_location,
                "created_at": created_at,
            }
        )
        if id is not UNSET:
            field_dict["id"] = id
        if booking_type is not UNSET:
            field_dict["booking_type"] = booking_type
        if old_amount is not UNSET:
            field_dict["old_amount"] = old_amount
        if new_amount is not UNSET:
            field_dict["new_amount"] = new_amount
        if note is not UNSET:
            field_dict["note"] = note

        return field_dict

    @classmethod
    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
        from ..models.inventory_entry import InventoryEntry
        from ..models.inventory_location import InventoryLocation

        d = dict(src_dict)
        entry = InventoryEntry.from_dict(d.pop("entry"))

        old_inventory_location = InventoryLocation.from_dict(d.pop("old_inventory_location"))

        new_inventory_location = InventoryLocation.from_dict(d.pop("new_inventory_location"))

        created_at = isoparse(d.pop("created_at"))

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

        _booking_type = d.pop("booking_type", UNSET)
        booking_type: BookingTypeEnum | Unset
        if isinstance(_booking_type, Unset):
            booking_type = UNSET
        else:
            booking_type = BookingTypeEnum(_booking_type)

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

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

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

        note = _parse_note(d.pop("note", UNSET))

        inventory_log = cls(
            entry=entry,
            old_inventory_location=old_inventory_location,
            new_inventory_location=new_inventory_location,
            created_at=created_at,
            id=id,
            booking_type=booking_type,
            old_amount=old_amount,
            new_amount=new_amount,
            note=note,
        )

        inventory_log.additional_properties = d
        return inventory_log

    @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
