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

import attr
from dateutil.parser import isoparse

from ..models.booking_barcode_type import BookingBarcodeType
from ..models.booking_field import BookingField
from ..models.booking_item import BookingItem
from ..models.booking_payment import BookingPayment
from ..models.booking_payment_option import BookingPaymentOption
from ..models.booking_reseller_source import BookingResellerSource
from ..models.booking_source import BookingSource
from ..models.booking_status import BookingStatus
from ..models.booking_total_currency import BookingTotalCurrency
from ..models.credit_card import CreditCard
from ..models.customer import Customer
from ..models.user import User
from ..types import UNSET, Unset

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


@attr.s(auto_attribs=True)
class Booking:
    """Booking object. Lists all the possible fields for all product types and scenarios. Most of them are not required
    when sending a new booking.<br>A single Booking can be used to book multiple products, each of them being a
    BookingItem. All the products of one booking have to be from the same supplier.

        Attributes:
            barcode_type (Union[Unset, BookingBarcodeType]): Declares the redemption code format customers will receive if
                the booking was created with barcodes.
            comments (Union[Unset, str]): Special requirements entered by the customer. Visible to both customer and
                supplier.
            commission (Union[Unset, float]): Calculated commission that the agent should receive for this booking
            coupon (Union[Unset, str]): Promo code that has been applied to this booking
            created_by (Union[Unset, User]): Internal Rezdy user details. This is a Rezdy application user who belongs to a
                Rezdy agent or supplier company.
            credit_card (Union[Unset, CreditCard]):  Credit card details.<p>Used to send payment details for a booking</p>
            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
            date_confirmed (Union[Unset, datetime.datetime]): Date this booking was confirmed
            date_created (Union[Unset, datetime.datetime]): Date this booking was created
            date_paid (Union[Unset, datetime.datetime]): Date this booking was fully paid
            date_reconciled (Union[Unset, datetime.datetime]): Date this booking was reconciled with the agent
            date_updated (Union[Unset, datetime.datetime]): Date this booking was last updated
            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[BookingItem]]): 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.
            payment_option (Union[Unset, BookingPaymentOption]): Payment option selected by the customer when making an
                online booking
            payments (Union[Unset, List[BookingPayment]]): List of payments recorded for this booking
            reseller_alias (Union[Unset, str]): Alias of the agent company attached to this booking
            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_name (Union[Unset, str]): Name 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_source (Union[Unset, BookingResellerSource]): Source of this booking viewed from the agent
            reseller_user (Union[Unset, User]): Internal Rezdy user details. This is a Rezdy application user who belongs to
                a Rezdy agent or supplier company.
            send_notifications (Union[Unset, bool]): Flag to control if a booking confirmation email should be send to the
                customer after this booking is created.<br>This will also send other types of customer notifications when setup
                by the supplier (I.e. SMS, Gift cards)  Default: True.
            source (Union[Unset, BookingSource]): Source of this booking viewed from the supplier
            source_channel (Union[Unset, str]): Agent code defined by the supplier
            source_referrer (Union[Unset, str]): Referrer code
            status (Union[Unset, BookingStatus]): Status of this booking
            supplier_alias (Union[Unset, str]): Alias of the company supplying this product
            supplier_id (Union[Unset, int]): Rezdy internal ID of the company supplying this product
            supplier_name (Union[Unset, str]): Name of the company supplying this product
            surcharge (Union[Unset, float]): Credit card surcharge calculated for this booking
            total_amount (Union[Unset, float]): Total booking amount
            total_currency (Union[Unset, BookingTotalCurrency]): Booking Currency
            total_due (Union[Unset, float]): Amount still due for this booking
            total_paid (Union[Unset, float]): Amount already paid
            vouchers (Union[Unset, List[str]]): List of vouchers (Gift cards) that have been redeemed to pay for this
                booking
    """

    barcode_type: Union[Unset, BookingBarcodeType] = UNSET
    comments: Union[Unset, str] = UNSET
    commission: Union[Unset, float] = UNSET
    coupon: Union[Unset, str] = UNSET
    created_by: Union[Unset, User] = UNSET
    credit_card: Union[Unset, CreditCard] = UNSET
    customer: Union[Unset, Customer] = UNSET
    date_confirmed: Union[Unset, datetime.datetime] = UNSET
    date_created: Union[Unset, datetime.datetime] = UNSET
    date_paid: Union[Unset, datetime.datetime] = UNSET
    date_reconciled: Union[Unset, datetime.datetime] = UNSET
    date_updated: Union[Unset, datetime.datetime] = UNSET
    fields: Union[Unset, List[BookingField]] = UNSET
    internal_notes: Union[Unset, str] = UNSET
    items: Union[Unset, List[BookingItem]] = UNSET
    order_number: Union[Unset, str] = UNSET
    payment_option: Union[Unset, BookingPaymentOption] = UNSET
    payments: Union[Unset, List[BookingPayment]] = UNSET
    reseller_alias: Union[Unset, str] = UNSET
    reseller_comments: Union[Unset, str] = UNSET
    reseller_id: Union[Unset, int] = UNSET
    reseller_name: Union[Unset, str] = UNSET
    reseller_reference: Union[Unset, str] = UNSET
    reseller_source: Union[Unset, BookingResellerSource] = UNSET
    reseller_user: Union[Unset, User] = UNSET
    send_notifications: Union[Unset, bool] = True
    source: Union[Unset, BookingSource] = UNSET
    source_channel: Union[Unset, str] = UNSET
    source_referrer: Union[Unset, str] = UNSET
    status: Union[Unset, BookingStatus] = UNSET
    supplier_alias: Union[Unset, str] = UNSET
    supplier_id: Union[Unset, int] = UNSET
    supplier_name: Union[Unset, str] = UNSET
    surcharge: Union[Unset, float] = UNSET
    total_amount: Union[Unset, float] = UNSET
    total_currency: Union[Unset, BookingTotalCurrency] = UNSET
    total_due: Union[Unset, float] = UNSET
    total_paid: Union[Unset, float] = UNSET
    vouchers: Union[Unset, List[str]] = UNSET
    additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict)

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

        comments = self.comments
        commission = self.commission
        coupon = self.coupon
        created_by: Union[Unset, Dict[str, Any]] = UNSET
        if not isinstance(self.created_by, Unset):
            created_by = self.created_by.to_dict()

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

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

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

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

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

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

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

        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
        payment_option: Union[Unset, str] = UNSET
        if not isinstance(self.payment_option, Unset):
            payment_option = self.payment_option.value

        payments: Union[Unset, List[Dict[str, Any]]] = UNSET
        if not isinstance(self.payments, Unset):
            payments = []
            for payments_item_data in self.payments:
                payments_item = payments_item_data.to_dict()

                payments.append(payments_item)

        reseller_alias = self.reseller_alias
        reseller_comments = self.reseller_comments
        reseller_id = self.reseller_id
        reseller_name = self.reseller_name
        reseller_reference = self.reseller_reference
        reseller_source: Union[Unset, str] = UNSET
        if not isinstance(self.reseller_source, Unset):
            reseller_source = self.reseller_source.value

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

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

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

        supplier_alias = self.supplier_alias
        supplier_id = self.supplier_id
        supplier_name = self.supplier_name
        surcharge = self.surcharge
        total_amount = self.total_amount
        total_currency: Union[Unset, str] = UNSET
        if not isinstance(self.total_currency, Unset):
            total_currency = self.total_currency.value

        total_due = self.total_due
        total_paid = self.total_paid
        vouchers: Union[Unset, List[str]] = UNSET
        if not isinstance(self.vouchers, Unset):
            vouchers = self.vouchers

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update({})
        if barcode_type is not UNSET:
            field_dict["barcodeType"] = barcode_type
        if comments is not UNSET:
            field_dict["comments"] = comments
        if commission is not UNSET:
            field_dict["commission"] = commission
        if coupon is not UNSET:
            field_dict["coupon"] = coupon
        if created_by is not UNSET:
            field_dict["createdBy"] = created_by
        if credit_card is not UNSET:
            field_dict["creditCard"] = credit_card
        if customer is not UNSET:
            field_dict["customer"] = customer
        if date_confirmed is not UNSET:
            field_dict["dateConfirmed"] = date_confirmed
        if date_created is not UNSET:
            field_dict["dateCreated"] = date_created
        if date_paid is not UNSET:
            field_dict["datePaid"] = date_paid
        if date_reconciled is not UNSET:
            field_dict["dateReconciled"] = date_reconciled
        if date_updated is not UNSET:
            field_dict["dateUpdated"] = date_updated
        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 payment_option is not UNSET:
            field_dict["paymentOption"] = payment_option
        if payments is not UNSET:
            field_dict["payments"] = payments
        if reseller_alias is not UNSET:
            field_dict["resellerAlias"] = reseller_alias
        if reseller_comments is not UNSET:
            field_dict["resellerComments"] = reseller_comments
        if reseller_id is not UNSET:
            field_dict["resellerId"] = reseller_id
        if reseller_name is not UNSET:
            field_dict["resellerName"] = reseller_name
        if reseller_reference is not UNSET:
            field_dict["resellerReference"] = reseller_reference
        if reseller_source is not UNSET:
            field_dict["resellerSource"] = reseller_source
        if reseller_user is not UNSET:
            field_dict["resellerUser"] = reseller_user
        if send_notifications is not UNSET:
            field_dict["sendNotifications"] = send_notifications
        if source is not UNSET:
            field_dict["source"] = source
        if source_channel is not UNSET:
            field_dict["sourceChannel"] = source_channel
        if source_referrer is not UNSET:
            field_dict["sourceReferrer"] = source_referrer
        if status is not UNSET:
            field_dict["status"] = status
        if supplier_alias is not UNSET:
            field_dict["supplierAlias"] = supplier_alias
        if supplier_id is not UNSET:
            field_dict["supplierId"] = supplier_id
        if supplier_name is not UNSET:
            field_dict["supplierName"] = supplier_name
        if surcharge is not UNSET:
            field_dict["surcharge"] = surcharge
        if total_amount is not UNSET:
            field_dict["totalAmount"] = total_amount
        if total_currency is not UNSET:
            field_dict["totalCurrency"] = total_currency
        if total_due is not UNSET:
            field_dict["totalDue"] = total_due
        if total_paid is not UNSET:
            field_dict["totalPaid"] = total_paid
        if vouchers is not UNSET:
            field_dict["vouchers"] = vouchers

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        _barcode_type = d.pop("barcodeType", UNSET)
        barcode_type: Union[Unset, BookingBarcodeType]
        if isinstance(_barcode_type, Unset):
            barcode_type = UNSET
        else:
            barcode_type = BookingBarcodeType(_barcode_type)

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

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

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

        _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)

        _credit_card = d.pop("creditCard", UNSET)
        credit_card: Union[Unset, CreditCard]
        if isinstance(_credit_card, Unset):
            credit_card = UNSET
        else:
            credit_card = CreditCard.from_dict(_credit_card)

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

        _date_confirmed = d.pop("dateConfirmed", UNSET)
        date_confirmed: Union[Unset, datetime.datetime]
        if isinstance(_date_confirmed, Unset):
            date_confirmed = UNSET
        else:
            date_confirmed = isoparse(_date_confirmed)

        _date_created = d.pop("dateCreated", UNSET)
        date_created: Union[Unset, datetime.datetime]
        if isinstance(_date_created, Unset):
            date_created = UNSET
        else:
            date_created = isoparse(_date_created)

        _date_paid = d.pop("datePaid", UNSET)
        date_paid: Union[Unset, datetime.datetime]
        if isinstance(_date_paid, Unset):
            date_paid = UNSET
        else:
            date_paid = isoparse(_date_paid)

        _date_reconciled = d.pop("dateReconciled", UNSET)
        date_reconciled: Union[Unset, datetime.datetime]
        if isinstance(_date_reconciled, Unset):
            date_reconciled = UNSET
        else:
            date_reconciled = isoparse(_date_reconciled)

        _date_updated = d.pop("dateUpdated", UNSET)
        date_updated: Union[Unset, datetime.datetime]
        if isinstance(_date_updated, Unset):
            date_updated = UNSET
        else:
            date_updated = isoparse(_date_updated)

        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 = BookingItem.from_dict(items_item_data)

            items.append(items_item)

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

        _payment_option = d.pop("paymentOption", UNSET)
        payment_option: Union[Unset, BookingPaymentOption]
        if isinstance(_payment_option, Unset):
            payment_option = UNSET
        else:
            payment_option = BookingPaymentOption(_payment_option)

        payments = []
        _payments = d.pop("payments", UNSET)
        for payments_item_data in _payments or []:
            payments_item = BookingPayment.from_dict(payments_item_data)

            payments.append(payments_item)

        reseller_alias = d.pop("resellerAlias", UNSET)

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

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

        reseller_name = d.pop("resellerName", UNSET)

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

        _reseller_source = d.pop("resellerSource", UNSET)
        reseller_source: Union[Unset, BookingResellerSource]
        if isinstance(_reseller_source, Unset):
            reseller_source = UNSET
        else:
            reseller_source = BookingResellerSource(_reseller_source)

        _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)

        send_notifications = d.pop("sendNotifications", UNSET)

        _source = d.pop("source", UNSET)
        source: Union[Unset, BookingSource]
        if isinstance(_source, Unset):
            source = UNSET
        else:
            source = BookingSource(_source)

        source_channel = d.pop("sourceChannel", UNSET)

        source_referrer = d.pop("sourceReferrer", UNSET)

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

        supplier_alias = d.pop("supplierAlias", UNSET)

        supplier_id = d.pop("supplierId", UNSET)

        supplier_name = d.pop("supplierName", UNSET)

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

        total_amount = d.pop("totalAmount", UNSET)

        _total_currency = d.pop("totalCurrency", UNSET)
        total_currency: Union[Unset, BookingTotalCurrency]
        if isinstance(_total_currency, Unset):
            total_currency = UNSET
        else:
            total_currency = BookingTotalCurrency(_total_currency)

        total_due = d.pop("totalDue", UNSET)

        total_paid = d.pop("totalPaid", UNSET)

        vouchers = cast(List[str], d.pop("vouchers", UNSET))

        booking = cls(
            barcode_type=barcode_type,
            comments=comments,
            commission=commission,
            coupon=coupon,
            created_by=created_by,
            credit_card=credit_card,
            customer=customer,
            date_confirmed=date_confirmed,
            date_created=date_created,
            date_paid=date_paid,
            date_reconciled=date_reconciled,
            date_updated=date_updated,
            fields=fields,
            internal_notes=internal_notes,
            items=items,
            order_number=order_number,
            payment_option=payment_option,
            payments=payments,
            reseller_alias=reseller_alias,
            reseller_comments=reseller_comments,
            reseller_id=reseller_id,
            reseller_name=reseller_name,
            reseller_reference=reseller_reference,
            reseller_source=reseller_source,
            reseller_user=reseller_user,
            send_notifications=send_notifications,
            source=source,
            source_channel=source_channel,
            source_referrer=source_referrer,
            status=status,
            supplier_alias=supplier_alias,
            supplier_id=supplier_id,
            supplier_name=supplier_name,
            surcharge=surcharge,
            total_amount=total_amount,
            total_currency=total_currency,
            total_due=total_due,
            total_paid=total_paid,
            vouchers=vouchers,
        )

        booking.additional_properties = d
        return booking

    @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
