import {
  Address,
  Location,
  Order,
  Product,
  ShopifyObject,
} from 'shopify-admin-api/dist/types/interfaces';


import {
  CountryCode,
  CurrencyCode
} from '../../types/ShopifyGraphQLAdminAPI';
import { NullableObject } from '../utilTypes';

export interface ShopifyRESTObject {
    id: number;
}

export type REST_MailingAddress = NullableObject<Address>;
export interface ShopifyRESTObjectWithGQLId extends ShopifyRESTObject {
  admin_graphql_api_id: string;
}

export interface RestProduct extends Product {}

export type REST_ProductVariant = Product['variants'][number];

// https://shopify.dev/docs/admin-api/rest/reference/inventory/inventoryitem
export interface REST_InventoryItem extends ShopifyRESTObject {
    // The unit cost of the inventory item.
    cost: string | null;

    // The two-digit code for the country where the inventory item was made.
    country_code_of_origin: CountryCode | null;

    // An array of country-specific Harmonized System (HS) codes for the item. Used to determine duties when shipping the inventory item to certain countries.
    country_harmonized_system_codes: {
        harmonized_system_code: string;
        country_code: CountryCode;
    }[];

    // The date and time (ISO 8601 format) when the inventory item was created.
    created_at: string;

    // The general Harmonized System (HS) code for the inventory item. Used if a country-specific HS code is not available.
    harmonized_system_code: number | null;

    // The ID of the inventory item.
    id: number;

    // The two-digit code for the province where the inventory item was made. Used only if the shipping provider for the inventory item is Canada Post.
    province_code_of_origin	: string | null;

    // The unique SKU (stock keeping unit) of the inventory item.
    sku: string;

    // Whether the inventory item is tracked. If true, then inventory quantity changes are tracked by Shopify.
    // "tracked": true
    tracked: boolean;

    // The date and time (ISO 8601 format) when the inventory item was last modified.
    updated_at: string;

    // Whether a customer needs to provide a shipping address when placing an order containing the inventory item.
    requires_shipping: boolean;

    admin_graphql_api_id: string;
}

export interface Shop extends ShopifyRESTObject {
    /**
     * The shop's street address. 
     */
    address1?: string;

    /**
     * The second line of the shop's street address.
     */
    address2?: string;

    /**
     * The city in which the shop is located.
     */
    city?: string;

    /**
     * The shop's country (by default equal to the two-letter country code).
     */
    country?: string;

    /**
     * The two-letter country code corresponding to the shop's country.
     */
    country_code?: string;

    /**
     * The shop's normalized country name.
     */
    country_name?: string;

    /**
     * The date and time when the shop was created.
     */
    created_at?: string;

    /**
     * The customer's email.
     */
    customer_email?: string;

    /**
     * The three-letter code for the currency that the shop accepts. 
     */
    currency?: string;

    /**
     * The shop's description.
     */
    description?: string;

    /**
     * The shop's domain.
     */
    domain?: string;

    /**
     * The contact email address for the shop.
     */
    email?: string;

    /**
     * Indicates whether the shop forces requests made to its resources to be made over SSL, using the HTTPS protocol. If true, HTTP requests will be redirected to HTTPS.
     */
    force_ssl?: boolean;

    /**
     * Present when a shop has a google app domain. It will be returned as a URL, else null. 
     */
    google_apps_domain?: string;

    /**
     * Present if a shop has google apps enabled. Those shops with this feature will be able to login to the google apps login.
     */
    google_apps_login_enabled?: boolean;

    /**
     * Geographic coordinate specifying the north/south location of a shop.
     */
    latitude?: number;

    /**
     * Geographic coordinate specifying the east/west location of a shop.
     */
    longitude?: number;

    /**
     * A string representing the way currency is formatted when the currency isn't specified.
     */
    money_format?: string;

    /**
     * A string representing the way currency is formatted when the currency is specified.
     */
    money_with_currency_format?: string;

    /**
     * The shop's 'myshopify.com' domain.
     */
    myshopify_domain?: string;

    /**
     * The name of the shop.
     */
    name?: string;

    /**
     * The name of the Shopify plan the shop is on.
     */
    plan_name?: string;

    /**
     * The display name of the Shopify plan the shop is on.
     */
    display_plan_name?: string;

    /**
     * Indicates whether the Storefront password protection is enabled.
     */
    password_enabled?: boolean;

    /**
     * The contact phone number for the shop.
     */
    phone?: string;

    /**
     * The shop's primary locale.
     */
    primary_locale?: string;

    /**
     * The shop's normalized province or state name.
     */
    province?: string;

    /**
     * The two-letter code for the shop's province or state.
     */
    province_code?: string;

    /**
     * A list of countries the shop ships products to, separated by a comma.
     */
    ships_to_countries?: string;

    /**
     * The username of the shop owner.
     */
    shop_owner?: string;

    /**
     * Unkown. Shopify documentation does not currently indicate what this property actually is.
     */
    source?: string;

    /**
     * Specifies whether or not taxes were charged for shipping. Although the Shopify docs don't indicate this, it's possible for the value to be null.
     */
    tax_shipping?: boolean;

    /**
     * The setting for whether applicable taxes are included in product prices. 
     */
    taxes_included?: boolean;

    /**
     * The setting for whether the shop is applying taxes on a per-county basis or not (US-only). Valid values are: "true" or "null."
     */
    county_taxes?: boolean;

    /**
     * The name of the timezone the shop is in.
     */
    timezone?: string;

    /**
     * The named timezone assigned by the IANA.
     */
    iana_timezone?: string;

    /**
     * The zip or postal code of the shop's address.
     */
    zip?: string;

    /**
     * Indicates whether the shop has web-based storefront or not.
     */
    has_storefront?: boolean;

    /**
     * Indicates whether the shop has any outstanding setup steps or not.
     */
    setup_required?: boolean;

    /**
     * Indicates whether the shop supports the Discounts api 
     */
    has_discounts?: boolean;

    /**
     * Indicates whether the shop supports the Gift Cards api 
     */
    has_gift_cards?: boolean;
}

export interface REST_LineItem extends ShopifyRESTObjectWithGQLId {
  /**
   * fulfillable_quantity: The amount available to fulfill, calculated as follows:
   * quantity - max(refunded_quantity, fulfilled_quantity) - pending_fulfilled_quantity - open_fulfilled_quantity
   */
  fulfillable_quantity: number;

  /**
   * @deprecated
   * The service provider that's fulfilling the item. Valid values: manual, or the name of the provider, such as amazon or shipwire. This field is due to be deprecated. Consider using ' "FulfillmentOrder#assigned_location instead.
   */
  fulfillment_service: string;

  /**
   * How far along an order is in terms line items fulfilled. Valid values: null, fulfilled, partial, and not_eligible.
   */
  fulfillment_status: null | 'fulfilled' | 'partial' | 'not_eligible';

  /**
   * The weight of the item in grams.
   * 
   * NOTE: This is the weight of the variant
   */
  grams: number;

  /**
   * The price of the item before discounts have been applied in the shop currency.
   */
  price: string;

  /**
   * The price of the line item in shop and presentment currencies.
   */
  price_set: RESTMoneyBag;

  /**
   * The ID of the product that the line item belongs to. Can be null if the original product associated with the order is deleted at a later date.
   */
  product_id: number | null;

  /**
   * The number of items that were purchased.
   */
  quantity: number;

  /**
   * Whether the item requires shipping.
   */
  requires_shipping: boolean;

  /**
   * The item's SKU (stock keeping unit).
   */
  sku: string;

  /**
   * The title of the product.
   */
  title: string;

  /**
   * The ID of the product variant.
   */
  variant_id: number;

  /**
   * The title of the product variant.
   */
  variant_title: string;

  /**
   * The name of the item's supplier.
   */
  vendor: string;

  /**
   * The name of the product variant.
   */
  name: string;

  /**
   * Whether the item is a gift card. If true, then the item is not taxed or considered for shipping charges.
   */
  gift_card: boolean | null;

  /**
   * An array of custom information for the item that has been added to the cart. Often used to provide product customization options.
   */
  properties: Property[];

  /**
   * Whether the item was taxable.
   */
  taxable: boolean;

  /**
   * A list of tax line objects, each of which details a tax applied to the item.
   */
  tax_lines: TaxLine[];

  /**
   * The payment gateway used to tender the tip, such as shopify_payments. Present only on tips.
   * TODO: Verify - this is a best guess since it's not on the documentation page
   */
  tip_payment_gateway?: string;

  /**
   * The payment method used to tender the tip, such as Visa. Present only on tips.
   */
  tip_payment_method?: string;

  /**
   * The total amount of the discount allocated to the line item in the shop currency. This field must be explicitly set using draft orders, Shopify scripts, or the API. Instead of using this field, Shopify recommends using discount_allocations, which provides the same information.
   */
  total_discount: string;

  /**
   * The total amount allocated to the line item in the presentment currency. Instead of using this field, Shopify recommends using discount_allocations, which provides the same information.
   */
  total_discount_set: RESTMoneyBag;

  /**
   * An ordered list of amounts allocated by discount applications. Each discount allocation is associated with a particular discount application.
   */
  discount_allocations: REST_DiscountAllocation[];

  /**
   * @deprecated
   * The location of the line item’s fulfillment origin. This field is due to be deprecated. Consider using ' "FulfillmentOrder#assigned_location_id instead.
   */
  origin_location: Location;

  // A list of duty objects, each containing information about a duty on the line item.
  duties: Duty[];
}

export interface Property {
  name: string;
  value: string | null | undefined;
}

export interface Duty {

  id: string;
  harmonized_system_code?: string | null | undefined;
  country_code_of_origin: CountryCode | null | undefined;
  shop_money: RESTMoneyV2;
  presentment_money?: RESTMoneyV2;
  tax_lines: TaxLine[];
  admin_graphql_api_id: string;
}

/**
 * title: The name of the tax.
 * price: The amount added to the order for this tax in the shop currency.
 * price_set: The amount added to the order for this tax in shop and presentment currencies.
 * rate: The tax rate applied to the order to calculate the tax price.
 * channel_liable: Whether the channel that submitted the tax line is liable for remitting. A value of null indicates unknown liability for the tax line.
 */
export interface TaxLine {
  title: string;
  price: string;
  price_set: RESTMoneyBag;
  rate: number;
  channel_liable: boolean | null;
}

/**
 * amount: The discount amount allocated to the line in the shop currency.
 * discount_application_index: The index of the associated discount application in the order's discount_applications list.
 * amount_set: The discount amount allocated to the line item in shop and presentment currencies.
 */
export interface REST_DiscountAllocation {
  amount?: string;
  discount_application_index: number;
  amount_set: RESTMoneyBag;
}

export interface REST_Customer extends ShopifyObject {
  id: number;
  admin_graphql_api_id: string;
  /**
   * Indicates whether the customer has consented to be sent marketing material via email.
   */
  accepts_marketing: boolean;
  /**
   * A list of addresses for the customer.
   */
  addresses?: REST_MailingAddress[];
  /**
   * The date and time when the customer was created.
   */
  created_at: string;
  /**
   * The three-letter code (ISO 4217 format) for the currency that the customer used when they paid for their last order. Defaults to the shop currency. Returns the shop currency for test orders.
   * (BETA)
   */
  currency: CurrencyCode | null;
  /**
   * The default address for the customer.
   */
  default_address: REST_MailingAddress;
  /**
   * The email address of the customer.
   */
  email: string | null;
  /**
   * The customer's first name.
   */
  first_name: string | null;
  /**
   * The customer's last name.
   */
  last_name: string | null;
  /**
   * The customer's first and last names.
   */
  name: string | null;
  /**
   * The id of the customer's last order.
   */
  last_order_id: number | null;
  /**
   * The name of the customer's last order. This is directly related to the Order's name field.
   */
  last_order_name: string | null;
  /**
   * The customer's identifier used with Multipass login
   */
  multipass_identifier: string | null;
  /**
   * A note about the customer.
   */
  note: string | null;
  /**
   * The number of orders associated with this customer.
   */
  orders_count: number | null;
  /**
   * The number of orders associated with this customer.
   */
  phone: string | null;
  /**
   * The state of the customer in a shop. Known values are 'disabled', 'decline', 'invited' and 'enabled'.
   */
  state: string;
  /**
   * Tags are additional short descriptors formatted as a string of comma-separated values.
   */
  tags: string;
  /**
   * Indicates whether the customer should be charged taxes when placing orders.
   */
  tax_exempt: boolean;
  /**
   * The total amount of money that the customer has spent at the shop. Note: the Shopify API may return this as a string value.
   */
  total_spent: string;

  tax_exemptions: string[];

  /**
   * The date and time when the customer information was updated.
   */
  updated_at: string;
  /**
   * States whether or not the email address has been verified.
   */
  verified_email: boolean;

  sms_marketing_consent: {
    state: string;
    opt_in_level: string;
    consent_updated_at: string;
    consent_collected_from: string;
  };

  email_marketing_consent: {
    state: string;
    opt_in_level: string;
    consent_updated_at: string;
  };
}

export type REST_Order = Omit<Order, 'line_items' | 'customer'> & {
    current_total_discounts: string;
    current_total_price: string;
    current_subtotal_price: string;
    current_total_tax: string;
    total_outstanding: string;
    current_total_discounts_set: RESTMoneyBag;
    current_total_duties_set: RESTMoneyBag;
    current_total_price_set: RESTMoneyBag;
    current_subtotal_price_set: RESTMoneyBag;
    current_total_tax_set: RESTMoneyBag;
    original_total_duties_set: RESTMoneyBag;
    line_items: REST_LineItem[];

    /**
     * Null if order was created via POS
     */
    customer?: REST_Customer | null;
  };

export interface RESTMoneyBag {
    shop_money: RESTMoneyV2;
    presentment_money?: RESTMoneyV2;
  }

export interface RESTMoneyV2 {
    amount: string;
    currency_code: CurrencyCode;
  }