import {
  MailingAddressFragment,
  Maybe,
  MoneyBagFragment,
  OrderModelFragment
} from '../../../types/ShopifyGraphQLAdminAPI';
import { ShopifyObjectModel } from '../ShopifyObject';

import {
  OmittedOrderPropsKey,
  OrderPropsKey,
} from './OrderPropsKeys';

export type MailingAddressParts<AddressType extends string> = {
  // Note: ALL of these blown up address fields should be optional because all addresses on the order are nullable
  // MailingAddress.id is required on id *assuming* the address itself is present.
  [
    K in Exclude<keyof MailingAddressFragment, '__typename'> as
    `${Uncapitalize<AddressType>}${Capitalize<K & string>}`
  ]: MailingAddressFragment[K];
};
type MoneyBagShopCurrencyAmount = Maybe<MoneyBagFragment['shopMoney']['amount']>;
export type BillingAddressProps = MailingAddressParts<'billingAddress'>;
export type DisplayAddressProps = MailingAddressParts<'displayAddress'>;
export type ShippingAddressProps = MailingAddressParts<'shippingAddress'>;

type SummarizedLineItemCurrencyKeys =
  'discountedTotal' |
  'discountedUnitPrice' |
  'originalTotal' |
  'originalUnitPrice' |
  'totalDiscount' |
  'unfulfilledDiscountedTotal' |
  'unfulfilledOriginalTotal';

type LineItemMoneyBagPropNames = `${SummarizedLineItemCurrencyKeys}Set`;
type LineItem = OrderModelFragment['lineItems']['edges'][number]['node'];
type LineItem__Light = Omit<LineItem, LineItemMoneyBagPropNames> &
  Record<SummarizedLineItemCurrencyKeys, MoneyBagShopCurrencyAmount>;

// Creating a Record with a unknown value type will ensure that the `OrderProps` type we intersect with
// has a more specific type
type _OrderProps = Record<OrderPropsKey, unknown>;
type OrderProps = _OrderProps &
  Omit<OrderModelFragment, OmittedOrderPropsKey> & {

  /**
   * In order to simplify the order model, we'll only be using shopMoney amount from MoneyBag objects.
   * `order.currencyCode` contains the currency of the store at the time of the order so we can use that to determine
   * the currency of all MoneyBag fields. We'll display amounts assuming the shop's currency.
   * 
   * We'll also remove the "set" from the property names since we're only dealing with numerical amounts now.
   */
   cartDiscountAmount: MoneyBagShopCurrencyAmount;
   currentCartDiscountAmount: MoneyBagShopCurrencyAmount;
   currentSubtotalPrice: MoneyBagShopCurrencyAmount;
   currentTotalDiscounts: MoneyBagShopCurrencyAmount;
   currentTotalDuties: MoneyBagShopCurrencyAmount;
   currentTotalPrice: MoneyBagShopCurrencyAmount;
   currentTotalTax: MoneyBagShopCurrencyAmount;
   netPayment: MoneyBagShopCurrencyAmount;
   originalTotalDuties: MoneyBagShopCurrencyAmount;
   originalTotalPrice: MoneyBagShopCurrencyAmount;
   refundDiscrepancy: MoneyBagShopCurrencyAmount;
   subtotalPrice: MoneyBagShopCurrencyAmount;
   totalCapturable: MoneyBagShopCurrencyAmount;
   totalDiscounts: MoneyBagShopCurrencyAmount;
   totalOutstanding: MoneyBagShopCurrencyAmount;
   totalPrice: MoneyBagShopCurrencyAmount;
   totalReceived: MoneyBagShopCurrencyAmount;
   totalRefunded: MoneyBagShopCurrencyAmount;
   totalRefundedShipping: MoneyBagShopCurrencyAmount;
   totalShippingPrice: MoneyBagShopCurrencyAmount;
   totalTax: MoneyBagShopCurrencyAmount;
   totalTipReceived: MoneyBagShopCurrencyAmount;

   // Reserve the `lineItems` property name for record link if they exist
   lineItems_json: LineItem__Light[];
   currentTaxLines_json: OrderModelFragment['currentTaxLines'];
   customAttributes_json: OrderModelFragment['customAttributes'];
   // Reserve the `customer` property name for record link
   customer_json: Omit<NonNullable<OrderModelFragment['customer']>, 'addresses'> | undefined;
  customerJourneySummary_json: OrderModelFragment['customerJourneySummary'];
  disputes_json: OrderModelFragment['disputes'];
  fulfillments_json: OrderModelFragment['fulfillments'];
  paymentCollectionDetails_json: OrderModelFragment['paymentCollectionDetails'];
  risks_json: OrderModelFragment['risks'];
  shippingLine_json: OrderModelFragment['shippingLine'];
  taxLines_json: OrderModelFragment['taxLines'];
  transactions_json: OrderModelFragment['transactions'];

  physicalLocationId: NonNullable<OrderModelFragment['physicalLocation']>['id'] | undefined;
  publicationId: NonNullable<OrderModelFragment['publication']>['id'] | undefined;
} & BillingAddressProps & DisplayAddressProps & ShippingAddressProps;

export const OrderTypeName = 'orders';
export type OrderTypeName = typeof OrderTypeName;

export interface Order extends ShopifyObjectModel {
  type: OrderTypeName;
  props: OrderProps;
}