<?php

namespace Square\Types;

use Square\Core\Json\JsonSerializableType;
use Square\Core\Json\JsonProperty;
use Square\Core\Types\ArrayType;
use Square\Core\Types\Union;

/**
 * Represents a line item in an order. Each line item describes a different
 * product to purchase, with its own quantity and price details.
 */
class OrderLineItem extends JsonSerializableType
{
    /**
     * @var ?string $uid A unique ID that identifies the line item only within this order.
     */
    #[JsonProperty('uid')]
    private ?string $uid;

    /**
     * @var ?string $name The name of the line item.
     */
    #[JsonProperty('name')]
    private ?string $name;

    /**
     * The count, or measurement, of a line item being purchased:
     *
     * If `quantity` is a whole number, and `quantity_unit` is not specified, then `quantity` denotes an item count.  For example: `3` apples.
     *
     * If `quantity` is a whole or decimal number, and `quantity_unit` is also specified, then `quantity` denotes a measurement.  For example: `2.25` pounds of broccoli.
     *
     * For more information, see [Specify item quantity and measurement unit](https://developer.squareup.com/docs/orders-api/create-orders#specify-item-quantity-and-measurement-unit).
     *
     * Line items with a quantity of `0` are automatically removed
     * when paying for or otherwise completing the order.
     *
     * @var string $quantity
     */
    #[JsonProperty('quantity')]
    private string $quantity;

    /**
     * @var ?OrderQuantityUnit $quantityUnit The measurement unit and decimal precision that this line item's quantity is measured in.
     */
    #[JsonProperty('quantity_unit')]
    private ?OrderQuantityUnit $quantityUnit;

    /**
     * @var ?string $note An optional note associated with the line item.
     */
    #[JsonProperty('note')]
    private ?string $note;

    /**
     * @var ?string $catalogObjectId The [CatalogItemVariation](entity:CatalogItemVariation) ID applied to this line item.
     */
    #[JsonProperty('catalog_object_id')]
    private ?string $catalogObjectId;

    /**
     * @var ?int $catalogVersion The version of the catalog object that this line item references.
     */
    #[JsonProperty('catalog_version')]
    private ?int $catalogVersion;

    /**
     * @var ?string $variationName The name of the variation applied to this line item.
     */
    #[JsonProperty('variation_name')]
    private ?string $variationName;

    /**
     * The type of line item: an itemized sale, a non-itemized sale (custom amount), or the
     * activation or reloading of a gift card.
     * See [OrderLineItemItemType](#type-orderlineitemitemtype) for possible values
     *
     * @var ?value-of<OrderLineItemItemType> $itemType
     */
    #[JsonProperty('item_type')]
    private ?string $itemType;

    /**
     * Application-defined data attached to this line item. Metadata fields are intended
     * to store descriptive references or associations with an entity in another system or store brief
     * information about the object. Square does not process this field; it only stores and returns it
     * in relevant API calls. Do not use metadata to store any sensitive information (such as personally
     * identifiable information or card details).
     *
     * Keys written by applications must be 60 characters or less and must be in the character set
     * `[a-zA-Z0-9_-]`. Entries can also include metadata generated by Square. These keys are prefixed
     * with a namespace, separated from the key with a ':' character.
     *
     * Values have a maximum length of 255 characters.
     *
     * An application can have up to 10 entries per metadata field.
     *
     * Entries written by applications are private and can only be read or modified by the same
     * application.
     *
     * For more information, see [Metadata](https://developer.squareup.com/docs/build-basics/metadata).
     *
     * @var ?array<string, ?string> $metadata
     */
    #[JsonProperty('metadata'), ArrayType(['string' => new Union('string', 'null')])]
    private ?array $metadata;

    /**
     * @var ?array<OrderLineItemModifier> $modifiers The [CatalogModifier](entity:CatalogModifier)s applied to this line item.
     */
    #[JsonProperty('modifiers'), ArrayType([OrderLineItemModifier::class])]
    private ?array $modifiers;

    /**
     * The list of references to taxes applied to this line item. Each
     * `OrderLineItemAppliedTax` has a `tax_uid` that references the `uid` of a
     * top-level `OrderLineItemTax` applied to the line item. On reads, the
     * amount applied is populated.
     *
     * An `OrderLineItemAppliedTax` is automatically created on every line
     * item for all `ORDER` scoped taxes added to the order. `OrderLineItemAppliedTax`
     * records for `LINE_ITEM` scoped taxes must be added in requests for the tax
     * to apply to any line items.
     *
     * To change the amount of a tax, modify the referenced top-level tax.
     *
     * @var ?array<OrderLineItemAppliedTax> $appliedTaxes
     */
    #[JsonProperty('applied_taxes'), ArrayType([OrderLineItemAppliedTax::class])]
    private ?array $appliedTaxes;

    /**
     * The list of references to discounts applied to this line item. Each
     * `OrderLineItemAppliedDiscount` has a `discount_uid` that references the `uid` of a top-level
     * `OrderLineItemDiscounts` applied to the line item. On reads, the amount
     * applied is populated.
     *
     * An `OrderLineItemAppliedDiscount` is automatically created on every line item for all
     * `ORDER` scoped discounts that are added to the order. `OrderLineItemAppliedDiscount` records
     * for `LINE_ITEM` scoped discounts must be added in requests for the discount to apply to any
     * line items.
     *
     * To change the amount of a discount, modify the referenced top-level discount.
     *
     * @var ?array<OrderLineItemAppliedDiscount> $appliedDiscounts
     */
    #[JsonProperty('applied_discounts'), ArrayType([OrderLineItemAppliedDiscount::class])]
    private ?array $appliedDiscounts;

    /**
     * The list of references to service charges applied to this line item. Each
     * `OrderLineItemAppliedServiceCharge` has a `service_charge_id` that references the `uid` of a
     * top-level `OrderServiceCharge` applied to the line item. On reads, the amount applied is
     * populated.
     *
     * To change the amount of a service charge, modify the referenced top-level service charge.
     *
     * @var ?array<OrderLineItemAppliedServiceCharge> $appliedServiceCharges
     */
    #[JsonProperty('applied_service_charges'), ArrayType([OrderLineItemAppliedServiceCharge::class])]
    private ?array $appliedServiceCharges;

    /**
     * @var ?Money $basePriceMoney The base price for a single unit of the line item.
     */
    #[JsonProperty('base_price_money')]
    private ?Money $basePriceMoney;

    /**
     * The total price of all item variations sold in this line item.
     * The price is calculated as `base_price_money` multiplied by `quantity`.
     * It does not include modifiers.
     *
     * @var ?Money $variationTotalPriceMoney
     */
    #[JsonProperty('variation_total_price_money')]
    private ?Money $variationTotalPriceMoney;

    /**
     * The amount of money made in gross sales for this line item.
     * The amount is calculated as the sum of the variation's total price and each modifier's total price.
     * For inclusive tax items in the US, Canada, and Japan, tax is deducted from `gross_sales_money`. For Europe and
     * Australia, inclusive tax remains as part of the gross sale calculation.
     *
     * @var ?Money $grossSalesMoney
     */
    #[JsonProperty('gross_sales_money')]
    private ?Money $grossSalesMoney;

    /**
     * @var ?Money $totalTaxMoney The total amount of tax money to collect for the line item.
     */
    #[JsonProperty('total_tax_money')]
    private ?Money $totalTaxMoney;

    /**
     * @var ?Money $totalDiscountMoney The total amount of discount money to collect for the line item.
     */
    #[JsonProperty('total_discount_money')]
    private ?Money $totalDiscountMoney;

    /**
     * @var ?Money $totalMoney The total amount of money to collect for this line item.
     */
    #[JsonProperty('total_money')]
    private ?Money $totalMoney;

    /**
     * Describes pricing adjustments that are blocked from automatic
     * application to a line item. For more information, see
     * [Apply Taxes and Discounts](https://developer.squareup.com/docs/orders-api/apply-taxes-and-discounts).
     *
     * @var ?OrderLineItemPricingBlocklists $pricingBlocklists
     */
    #[JsonProperty('pricing_blocklists')]
    private ?OrderLineItemPricingBlocklists $pricingBlocklists;

    /**
     * @var ?Money $totalServiceChargeMoney The total amount of apportioned service charge money to collect for the line item.
     */
    #[JsonProperty('total_service_charge_money')]
    private ?Money $totalServiceChargeMoney;

    /**
     * @param array{
     *   quantity: string,
     *   uid?: ?string,
     *   name?: ?string,
     *   quantityUnit?: ?OrderQuantityUnit,
     *   note?: ?string,
     *   catalogObjectId?: ?string,
     *   catalogVersion?: ?int,
     *   variationName?: ?string,
     *   itemType?: ?value-of<OrderLineItemItemType>,
     *   metadata?: ?array<string, ?string>,
     *   modifiers?: ?array<OrderLineItemModifier>,
     *   appliedTaxes?: ?array<OrderLineItemAppliedTax>,
     *   appliedDiscounts?: ?array<OrderLineItemAppliedDiscount>,
     *   appliedServiceCharges?: ?array<OrderLineItemAppliedServiceCharge>,
     *   basePriceMoney?: ?Money,
     *   variationTotalPriceMoney?: ?Money,
     *   grossSalesMoney?: ?Money,
     *   totalTaxMoney?: ?Money,
     *   totalDiscountMoney?: ?Money,
     *   totalMoney?: ?Money,
     *   pricingBlocklists?: ?OrderLineItemPricingBlocklists,
     *   totalServiceChargeMoney?: ?Money,
     * } $values
     */
    public function __construct(
        array $values,
    ) {
        $this->uid = $values['uid'] ?? null;
        $this->name = $values['name'] ?? null;
        $this->quantity = $values['quantity'];
        $this->quantityUnit = $values['quantityUnit'] ?? null;
        $this->note = $values['note'] ?? null;
        $this->catalogObjectId = $values['catalogObjectId'] ?? null;
        $this->catalogVersion = $values['catalogVersion'] ?? null;
        $this->variationName = $values['variationName'] ?? null;
        $this->itemType = $values['itemType'] ?? null;
        $this->metadata = $values['metadata'] ?? null;
        $this->modifiers = $values['modifiers'] ?? null;
        $this->appliedTaxes = $values['appliedTaxes'] ?? null;
        $this->appliedDiscounts = $values['appliedDiscounts'] ?? null;
        $this->appliedServiceCharges = $values['appliedServiceCharges'] ?? null;
        $this->basePriceMoney = $values['basePriceMoney'] ?? null;
        $this->variationTotalPriceMoney = $values['variationTotalPriceMoney'] ?? null;
        $this->grossSalesMoney = $values['grossSalesMoney'] ?? null;
        $this->totalTaxMoney = $values['totalTaxMoney'] ?? null;
        $this->totalDiscountMoney = $values['totalDiscountMoney'] ?? null;
        $this->totalMoney = $values['totalMoney'] ?? null;
        $this->pricingBlocklists = $values['pricingBlocklists'] ?? null;
        $this->totalServiceChargeMoney = $values['totalServiceChargeMoney'] ?? null;
    }

    /**
     * @return ?string
     */
    public function getUid(): ?string
    {
        return $this->uid;
    }

    /**
     * @param ?string $value
     */
    public function setUid(?string $value = null): self
    {
        $this->uid = $value;
        return $this;
    }

    /**
     * @return ?string
     */
    public function getName(): ?string
    {
        return $this->name;
    }

    /**
     * @param ?string $value
     */
    public function setName(?string $value = null): self
    {
        $this->name = $value;
        return $this;
    }

    /**
     * @return string
     */
    public function getQuantity(): string
    {
        return $this->quantity;
    }

    /**
     * @param string $value
     */
    public function setQuantity(string $value): self
    {
        $this->quantity = $value;
        return $this;
    }

    /**
     * @return ?OrderQuantityUnit
     */
    public function getQuantityUnit(): ?OrderQuantityUnit
    {
        return $this->quantityUnit;
    }

    /**
     * @param ?OrderQuantityUnit $value
     */
    public function setQuantityUnit(?OrderQuantityUnit $value = null): self
    {
        $this->quantityUnit = $value;
        return $this;
    }

    /**
     * @return ?string
     */
    public function getNote(): ?string
    {
        return $this->note;
    }

    /**
     * @param ?string $value
     */
    public function setNote(?string $value = null): self
    {
        $this->note = $value;
        return $this;
    }

    /**
     * @return ?string
     */
    public function getCatalogObjectId(): ?string
    {
        return $this->catalogObjectId;
    }

    /**
     * @param ?string $value
     */
    public function setCatalogObjectId(?string $value = null): self
    {
        $this->catalogObjectId = $value;
        return $this;
    }

    /**
     * @return ?int
     */
    public function getCatalogVersion(): ?int
    {
        return $this->catalogVersion;
    }

    /**
     * @param ?int $value
     */
    public function setCatalogVersion(?int $value = null): self
    {
        $this->catalogVersion = $value;
        return $this;
    }

    /**
     * @return ?string
     */
    public function getVariationName(): ?string
    {
        return $this->variationName;
    }

    /**
     * @param ?string $value
     */
    public function setVariationName(?string $value = null): self
    {
        $this->variationName = $value;
        return $this;
    }

    /**
     * @return ?value-of<OrderLineItemItemType>
     */
    public function getItemType(): ?string
    {
        return $this->itemType;
    }

    /**
     * @param ?value-of<OrderLineItemItemType> $value
     */
    public function setItemType(?string $value = null): self
    {
        $this->itemType = $value;
        return $this;
    }

    /**
     * @return ?array<string, ?string>
     */
    public function getMetadata(): ?array
    {
        return $this->metadata;
    }

    /**
     * @param ?array<string, ?string> $value
     */
    public function setMetadata(?array $value = null): self
    {
        $this->metadata = $value;
        return $this;
    }

    /**
     * @return ?array<OrderLineItemModifier>
     */
    public function getModifiers(): ?array
    {
        return $this->modifiers;
    }

    /**
     * @param ?array<OrderLineItemModifier> $value
     */
    public function setModifiers(?array $value = null): self
    {
        $this->modifiers = $value;
        return $this;
    }

    /**
     * @return ?array<OrderLineItemAppliedTax>
     */
    public function getAppliedTaxes(): ?array
    {
        return $this->appliedTaxes;
    }

    /**
     * @param ?array<OrderLineItemAppliedTax> $value
     */
    public function setAppliedTaxes(?array $value = null): self
    {
        $this->appliedTaxes = $value;
        return $this;
    }

    /**
     * @return ?array<OrderLineItemAppliedDiscount>
     */
    public function getAppliedDiscounts(): ?array
    {
        return $this->appliedDiscounts;
    }

    /**
     * @param ?array<OrderLineItemAppliedDiscount> $value
     */
    public function setAppliedDiscounts(?array $value = null): self
    {
        $this->appliedDiscounts = $value;
        return $this;
    }

    /**
     * @return ?array<OrderLineItemAppliedServiceCharge>
     */
    public function getAppliedServiceCharges(): ?array
    {
        return $this->appliedServiceCharges;
    }

    /**
     * @param ?array<OrderLineItemAppliedServiceCharge> $value
     */
    public function setAppliedServiceCharges(?array $value = null): self
    {
        $this->appliedServiceCharges = $value;
        return $this;
    }

    /**
     * @return ?Money
     */
    public function getBasePriceMoney(): ?Money
    {
        return $this->basePriceMoney;
    }

    /**
     * @param ?Money $value
     */
    public function setBasePriceMoney(?Money $value = null): self
    {
        $this->basePriceMoney = $value;
        return $this;
    }

    /**
     * @return ?Money
     */
    public function getVariationTotalPriceMoney(): ?Money
    {
        return $this->variationTotalPriceMoney;
    }

    /**
     * @param ?Money $value
     */
    public function setVariationTotalPriceMoney(?Money $value = null): self
    {
        $this->variationTotalPriceMoney = $value;
        return $this;
    }

    /**
     * @return ?Money
     */
    public function getGrossSalesMoney(): ?Money
    {
        return $this->grossSalesMoney;
    }

    /**
     * @param ?Money $value
     */
    public function setGrossSalesMoney(?Money $value = null): self
    {
        $this->grossSalesMoney = $value;
        return $this;
    }

    /**
     * @return ?Money
     */
    public function getTotalTaxMoney(): ?Money
    {
        return $this->totalTaxMoney;
    }

    /**
     * @param ?Money $value
     */
    public function setTotalTaxMoney(?Money $value = null): self
    {
        $this->totalTaxMoney = $value;
        return $this;
    }

    /**
     * @return ?Money
     */
    public function getTotalDiscountMoney(): ?Money
    {
        return $this->totalDiscountMoney;
    }

    /**
     * @param ?Money $value
     */
    public function setTotalDiscountMoney(?Money $value = null): self
    {
        $this->totalDiscountMoney = $value;
        return $this;
    }

    /**
     * @return ?Money
     */
    public function getTotalMoney(): ?Money
    {
        return $this->totalMoney;
    }

    /**
     * @param ?Money $value
     */
    public function setTotalMoney(?Money $value = null): self
    {
        $this->totalMoney = $value;
        return $this;
    }

    /**
     * @return ?OrderLineItemPricingBlocklists
     */
    public function getPricingBlocklists(): ?OrderLineItemPricingBlocklists
    {
        return $this->pricingBlocklists;
    }

    /**
     * @param ?OrderLineItemPricingBlocklists $value
     */
    public function setPricingBlocklists(?OrderLineItemPricingBlocklists $value = null): self
    {
        $this->pricingBlocklists = $value;
        return $this;
    }

    /**
     * @return ?Money
     */
    public function getTotalServiceChargeMoney(): ?Money
    {
        return $this->totalServiceChargeMoney;
    }

    /**
     * @param ?Money $value
     */
    public function setTotalServiceChargeMoney(?Money $value = null): self
    {
        $this->totalServiceChargeMoney = $value;
        return $this;
    }

    /**
     * @return string
     */
    public function __toString(): string
    {
        return $this->toJson();
    }
}
