from typing import Any, Dict, List, Type, TypeVar, Union

import attr

from ..models.booking_field import BookingField
from ..models.booking_item_create import BookingItemCreate
from ..models.booking_update_status import BookingUpdateStatus
from ..models.customer import Customer
from ..models.user import User
from ..types import UNSET, Unset

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


@attr.s(auto_attribs=True)
class BookingUpdate:
    """Booking update object used to update a booking in Rezdy's system.

    Attributes:
        created_by (Union[Unset, User]): Internal Rezdy user details. This is a Rezdy application user who belongs to a
            Rezdy agent or supplier company.
        customer (Union[Unset, Customer]): The customer is the person making the booking, and most of the time paying
            for it.<br>It differs from Participants, who are the people attending a tour
        fields (Union[Unset, List[BookingField]]): List of custom fields that are required "once per booking" by all the
            products in this booking
        internal_notes (Union[Unset, str]): Comments only visible internally by the supplier
        items (Union[Unset, List[BookingItemCreate]]): List of items in this booking. A booking can contain multiple
            products. Each BookingItem is a separate product with its own set of quantities and participant details.
        order_number (Union[Unset, str]): Order number. This is the number you should give to customers and print on
            booking confirmations. Order number is generated by the system, therefore, even if it is specified in the
            booking request, it will be overwritten.
        reseller_comments (Union[Unset, str]): Comments only visible by the agent and the supplier. This should be used
            by the agent to send voucher numbers/redemption codes to suppliers.
        reseller_id (Union[Unset, int]): Rezdy internal ID of the agent company attached to this booking
        reseller_reference (Union[Unset, str]): External reseller reference, can be used to pass internal booking
            number. This reference will be shown to a supplier, also it will appear on reports and can be used to filter
            orders. Maxiumum number of characters is 30
        reseller_user (Union[Unset, User]): Internal Rezdy user details. This is a Rezdy application user who belongs to
            a Rezdy agent or supplier company.
        status (Union[Unset, BookingUpdateStatus]): Status of this booking
    """

    created_by: Union[Unset, User] = UNSET
    customer: Union[Unset, Customer] = UNSET
    fields: Union[Unset, List[BookingField]] = UNSET
    internal_notes: Union[Unset, str] = UNSET
    items: Union[Unset, List[BookingItemCreate]] = UNSET
    order_number: Union[Unset, str] = UNSET
    reseller_comments: Union[Unset, str] = UNSET
    reseller_id: Union[Unset, int] = UNSET
    reseller_reference: Union[Unset, str] = UNSET
    reseller_user: Union[Unset, User] = UNSET
    status: Union[Unset, BookingUpdateStatus] = UNSET
    additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        created_by: Union[Unset, Dict[str, Any]] = UNSET
        if not isinstance(self.created_by, Unset):
            created_by = self.created_by.to_dict()

        customer: Union[Unset, Dict[str, Any]] = UNSET
        if not isinstance(self.customer, Unset):
            customer = self.customer.to_dict()

        fields: Union[Unset, List[Dict[str, Any]]] = UNSET
        if not isinstance(self.fields, Unset):
            fields = []
            for fields_item_data in self.fields:
                fields_item = fields_item_data.to_dict()

                fields.append(fields_item)

        internal_notes = self.internal_notes
        items: Union[Unset, List[Dict[str, Any]]] = UNSET
        if not isinstance(self.items, Unset):
            items = []
            for items_item_data in self.items:
                items_item = items_item_data.to_dict()

                items.append(items_item)

        order_number = self.order_number
        reseller_comments = self.reseller_comments
        reseller_id = self.reseller_id
        reseller_reference = self.reseller_reference
        reseller_user: Union[Unset, Dict[str, Any]] = UNSET
        if not isinstance(self.reseller_user, Unset):
            reseller_user = self.reseller_user.to_dict()

        status: Union[Unset, str] = UNSET
        if not isinstance(self.status, Unset):
            status = self.status.value

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update({})
        if created_by is not UNSET:
            field_dict["createdBy"] = created_by
        if customer is not UNSET:
            field_dict["customer"] = customer
        if fields is not UNSET:
            field_dict["fields"] = fields
        if internal_notes is not UNSET:
            field_dict["internalNotes"] = internal_notes
        if items is not UNSET:
            field_dict["items"] = items
        if order_number is not UNSET:
            field_dict["orderNumber"] = order_number
        if reseller_comments is not UNSET:
            field_dict["resellerComments"] = reseller_comments
        if reseller_id is not UNSET:
            field_dict["resellerId"] = reseller_id
        if reseller_reference is not UNSET:
            field_dict["resellerReference"] = reseller_reference
        if reseller_user is not UNSET:
            field_dict["resellerUser"] = reseller_user
        if status is not UNSET:
            field_dict["status"] = status

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        _created_by = d.pop("createdBy", UNSET)
        created_by: Union[Unset, User]
        if isinstance(_created_by, Unset):
            created_by = UNSET
        else:
            created_by = User.from_dict(_created_by)

        _customer = d.pop("customer", UNSET)
        customer: Union[Unset, Customer]
        if isinstance(_customer, Unset):
            customer = UNSET
        else:
            customer = Customer.from_dict(_customer)

        fields = []
        _fields = d.pop("fields", UNSET)
        for fields_item_data in _fields or []:
            fields_item = BookingField.from_dict(fields_item_data)

            fields.append(fields_item)

        internal_notes = d.pop("internalNotes", UNSET)

        items = []
        _items = d.pop("items", UNSET)
        for items_item_data in _items or []:
            items_item = BookingItemCreate.from_dict(items_item_data)

            items.append(items_item)

        order_number = d.pop("orderNumber", UNSET)

        reseller_comments = d.pop("resellerComments", UNSET)

        reseller_id = d.pop("resellerId", UNSET)

        reseller_reference = d.pop("resellerReference", UNSET)

        _reseller_user = d.pop("resellerUser", UNSET)
        reseller_user: Union[Unset, User]
        if isinstance(_reseller_user, Unset):
            reseller_user = UNSET
        else:
            reseller_user = User.from_dict(_reseller_user)

        _status = d.pop("status", UNSET)
        status: Union[Unset, BookingUpdateStatus]
        if isinstance(_status, Unset):
            status = UNSET
        else:
            status = BookingUpdateStatus(_status)

        booking_update = cls(
            created_by=created_by,
            customer=customer,
            fields=fields,
            internal_notes=internal_notes,
            items=items,
            order_number=order_number,
            reseller_comments=reseller_comments,
            reseller_id=reseller_id,
            reseller_reference=reseller_reference,
            reseller_user=reseller_user,
            status=status,
        )

        booking_update.additional_properties = d
        return booking_update

    @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
