import {Address, AddressParam} from './shared';
import {PaymentMethod} from './payment-methods';

/**
 * The PaymentIntent object.
 */
export interface PaymentIntent {
  /**
   * Unique identifier for the object.
   */
  id: string;

  /**
   * String representing the object's type. Objects of the same type share the same value.
   */
  object: 'payment_intent';

  /**
   * Amount intended to be collected by this PaymentIntent. A positive integer representing how much to charge in the [smallest currency unit](https://stripe.com/docs/currencies#zero-decimal) (e.g., 100 cents to charge $1.00 or 100 to charge ¥100, a zero-decimal currency). The minimum amount is $0.50 US or [equivalent in charge currency](https://stripe.com/docs/currencies#minimum-and-maximum-charge-amounts). The amount value supports up to eight digits (e.g., a value of 99999999 for a USD charge of $999,999.99).
   */
  amount: number;

  /**
   * Populated when `status` is `canceled`, this is the time at which the PaymentIntent was canceled. Measured in seconds since the Unix epoch.
   */
  canceled_at: number | null;

  /**
   * Reason for cancellation of this PaymentIntent, either user-provided (`duplicate`, `fraudulent`, `requested_by_customer`, or `abandoned`) or generated by Stripe internally (`failed_invoice`, `void_invoice`, or `automatic`).
   */
  cancellation_reason: PaymentIntent.CancellationReason | null;

  /**
   * Controls when the funds will be captured from the customer's account.
   */
  capture_method: PaymentIntent.CaptureMethod;

  /**
   * The client secret of this PaymentIntent. Used for client-side retrieval using a publishable key.
   *
   * The client secret can be used to complete a payment from your frontend. It should not be stored, logged, embedded in URLs, or exposed to anyone other than the customer. Make sure that you have TLS enabled on any page that includes the client secret.
   *
   * Refer to our docs to [accept a payment](https://stripe.com/docs/payments/accept-a-payment) and learn about how `client_secret` should be handled.
   */
  client_secret: string | null;

  confirmation_method: PaymentIntent.ConfirmationMethod;

  /**
   * Time at which the object was created. Measured in seconds since the Unix epoch.
   */
  created: number;

  /**
   * Three-letter [ISO currency code](https://www.iso.org/iso-4217-currency-codes.html), in lowercase. Must be a [supported currency](https://stripe.com/docs/currencies).
   */
  currency: string;

  /**
   * An arbitrary string attached to the object. Often useful for displaying to users.
   */
  description: string | null;

  /**
   * The payment error encountered in the previous PaymentIntent confirmation. It will be cleared if the PaymentIntent is later updated for any reason.
   */
  last_payment_error: PaymentIntent.LastPaymentError | null;

  /**
   * Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode.
   */
  livemode: boolean;

  /**
   * If present, this property tells you what actions you need to take in order for your customer to fulfill a payment using the provided source.
   */
  next_action: PaymentIntent.NextAction | null;

  /**
   * ID of the payment method used in this PaymentIntent, or the PaymentMethod itself if this field is expanded.
   */
  payment_method: string | null | PaymentMethod;

  /**
   * The list of payment method types (e.g. card) that this PaymentIntent is allowed to use.
   */
  payment_method_types: Array<string>;

  /**
   * Email address that the receipt for the resulting payment will be sent to.
   */
  receipt_email: string | null;

  /**
   * Indicates that you intend to make future payments with this PaymentIntent's payment method.
   *
   * If present, the payment method used with this PaymentIntent can be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer, even after the transaction completes.
   *
   * For more, learn to [save card details after a payment](https://stripe.com/docs/payments/save-after-payment).
   *
   * Stripe uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules. For example, if your customer is impacted by [SCA](https://stripe.com/docs/strong-customer-authentication), using `off_session` will ensure that they are authenticated while processing this PaymentIntent. You will then be able to collect [off-session payments](https://stripe.com/docs/payments/cards/charging-saved-cards#off-session-payments-with-saved-cards) for this customer.
   */
  setup_future_usage: PaymentIntent.SetupFutureUsage | null;

  /**
   * Shipping information for this PaymentIntent.
   */
  shipping: PaymentIntent.Shipping | null;

  /**
   * Status of this PaymentIntent, one of `requires_payment_method`, `requires_confirmation`, `requires_action`, `processing`, `requires_capture`, `canceled`, or `succeeded`. Read more about each PaymentIntent [status](https://stripe.com/docs/payments/intents#intent-statuses).
   */
  status: PaymentIntent.Status;
}

export namespace PaymentIntent {
  export type CancellationReason =
    | 'abandoned'
    | 'automatic'
    | 'duplicate'
    | 'failed_invoice'
    | 'fraudulent'
    | 'requested_by_customer'
    | 'void_invoice';

  export type CaptureMethod = 'automatic' | 'manual';

  export type ConfirmationMethod = 'automatic' | 'manual';

  export interface LastPaymentError {
    /**
     * For card errors, the ID of the failed charge.
     */
    charge?: string;

    /**
     * For some errors that could be handled programmatically, a short string indicating the [error code](https://stripe.com/docs/error-codes) reported.
     */
    code?: string;

    /**
     * For card errors resulting from a card issuer decline, a short string indicating the [card issuer's reason for the decline](https://stripe.com/docs/declines#issuer-declines) if they provide one.
     */
    decline_code?: string;

    /**
     * A URL to more information about the [error code](https://stripe.com/docs/error-codes) reported.
     */
    doc_url?: string;

    /**
     * A human-readable message providing more details about the error. For card errors, these messages can be shown to your users.
     */
    message?: string;

    /**
     * If the error is parameter-specific, the parameter related to the error. For example, you can use this to display a message near the correct form field.
     */
    param?: string;

    payment_method?: PaymentMethod;

    /**
     * The type of error returned. One of `api_connection_error`, `api_error`, `authentication_error`, `card_error`, `idempotency_error`, `invalid_request_error`, or `rate_limit_error`
     */
    type: LastPaymentError.Type;
  }

  export namespace LastPaymentError {
    export type Type =
      | 'api_connection_error'
      | 'api_error'
      | 'authentication_error'
      | 'card_error'
      | 'idempotency_error'
      | 'invalid_request_error'
      | 'rate_limit_error';
  }

  export interface NextAction {
    redirect_to_url?: NextAction.RedirectToUrl;

    /**
     * Type of the next action to perform, one of `redirect_to_url`, `use_stripe_sdk` or `wechat_pay_display_qr_code`.
     */
    type: string;

    /**
     * Wechat Pay display qrcode
     */
    wechat_pay_display_qr_code?: NextAction.WechatPayDisplayQrCode;
  }

  export namespace NextAction {
    export interface RedirectToUrl {
      /**
       * If the customer does not exit their browser while authenticating, they will be redirected to this specified URL after completion.
       */
      return_url: string | null;

      /**
       * The URL you must redirect your customer to in order to authenticate the payment.
       */
      url: string | null;
    }
    export interface WechatPayDisplayQrCode {
      /**
       * Render and display `paymentIntent.next_action.wechat_pay_display_qr_code.data` as a QR code on your checkout page.
       */
      data: string;

      /**
       * Use `paymentIntent.next_action.wechat_pay_display_qr_code.image_data_url` as an image source.
       */
      image_data_url: string;
    }
  }

  export type SetupFutureUsage = 'off_session' | 'on_session';

  export interface Shipping {
    address?: Address;

    /**
     * The delivery service that shipped a physical product, such as Fedex, UPS, USPS, etc.
     */
    carrier?: string | null;

    /**
     * Recipient name.
     */
    name?: string | null;

    /**
     * Recipient phone (including extension).
     */
    phone?: string | null;

    /**
     * The tracking number for a physical product, obtained from the delivery service. If multiple tracking numbers were generated for this purchase, please separate them with commas.
     */
    tracking_number?: string | null;
  }

  export type Status =
    | 'canceled'
    | 'processing'
    | 'requires_action'
    | 'requires_capture'
    | 'requires_confirmation'
    | 'requires_payment_method'
    | 'succeeded';
}

export interface PaymentIntentConfirmParams {
  /**
   * This hash contains details about the Mandate to create
   */
  mandate_data?: {[k: string]: any};

  /**
   * Email address that the receipt for the resulting payment will be sent to.
   */
  receipt_email?: string | '';

  /**
   * The URL to redirect your customer back to after they authenticate or cancel their payment on the payment method's app or site.
   * If you'd prefer to redirect to a mobile application, you can alternatively supply an application URI scheme.
   * This parameter is only used for cards and other redirect-based payment methods.
   */
  return_url?: string;

  /**
   * If the PaymentIntent has a `payment_method` and a `customer` or if you're attaching a payment method to the PaymentIntent in this request, you can pass `save_payment_method=true` to save the payment method to the customer. Defaults to `false`.
   *
   * If the payment method is already saved to a customer, this does nothing. If this type of payment method cannot be saved to a customer, the request will error.
   *
   * _Note that saving a payment method using this parameter does not guarantee that the payment method can be charged._ To ensure that only payment methods which can be charged are saved to a customer, you can [manually save](https://stripe.com/docs/api/customers/create#create_customer-source) the payment method in response to the [`payment_intent.succeeded` webhook](https://stripe.com/docs/api/events/types#event_types-payment_intent.succeeded).
   */
  save_payment_method?: boolean;

  /**
   * Indicates that you intend to make future payments with this PaymentIntent's payment method.
   *
   * If present, the payment method used with this PaymentIntent can be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer, even after the transaction completes.
   *
   * Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. Use `off_session` if your customer may or may not be in your checkout flow.
   *
   * Stripe uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules. For example, if your customer is impacted by [SCA](https://stripe.com/docs/strong-customer-authentication), using `off_session` will ensure that they are authenticated while processing this PaymentIntent. You will then be able to collect [off-session payments](https://stripe.com/docs/payments/cards/charging-saved-cards#off-session-payments-with-saved-cards) for this customer.
   *
   * If `setup_future_usage` is already set and you are performing a request using a publishable key, you may only update the value from `on_session` to `off_session`.
   */
  setup_future_usage?: PaymentIntentConfirmParams.SetupFutureUsage | null;

  /**
   * Shipping information for this PaymentIntent.
   */
  shipping?: PaymentIntentConfirmParams.Shipping | null;
}

export namespace PaymentIntentConfirmParams {
  export type SetupFutureUsage = 'off_session' | 'on_session';

  export interface Shipping {
    /**
     * Shipping address.
     */
    address: AddressParam;

    /**
     * The delivery service that shipped a physical product, such as Fedex, UPS, USPS, etc.
     */
    carrier?: string;

    /**
     * Recipient name.
     */
    name: string;

    /**
     * Recipient phone (including extension).
     */
    phone?: string;

    /**
     * The tracking number for a physical product, obtained from the delivery service. If multiple tracking numbers were generated for this purchase, please separate them with commas.
     */
    tracking_number?: string;
  }
}
