import type { CartActionError } from './errors';
import type { Dispatch } from 'react';

export type ShoppingCartReducerDispatch = ( action: ShoppingCartAction ) => void;

export type ShoppingCartReducer = (
	state: ShoppingCartState,
	action: ShoppingCartAction
) => ShoppingCartState;

export type CartKey = number | 'no-user' | 'no-site';

export type GetCart = ( cartKey: CartKey ) => Promise< ResponseCart >;
export type SetCart = ( cartKey: CartKey, requestCart: RequestCart ) => Promise< ResponseCart >;

export interface ShoppingCartManagerOptions {
	refetchOnWindowFocus?: boolean;
	defaultCartKey?: CartKey;
}

export type GetManagerForKey = ( cartKey: CartKey | undefined ) => ShoppingCartManager;
export type GetCartKeyForSiteSlug = ( siteSlug: string ) => Promise< CartKey >;

export interface ShoppingCartManagerClient {
	forCartKey: GetManagerForKey;
	getCartKeyForSiteSlug: GetCartKeyForSiteSlug;
}

export type UnsubscribeFunction = () => void;

export type SubscribeCallback = () => void;

export type ShoppingCartManagerSubscribe = ( callback: SubscribeCallback ) => UnsubscribeFunction;

export interface SubscriptionManager {
	subscribe: ShoppingCartManagerSubscribe;
	notifySubscribers: () => void;
}

export interface ShoppingCartManagerState {
	isLoading: boolean;
	loadingError: string | null | undefined;
	loadingErrorType: ShoppingCartError | undefined;
	isPendingUpdate: boolean;
	responseCart: ResponseCart;
	couponStatus: CouponStatus;
}

type WaitForReady = () => Promise< ResponseCart >;

export type ShoppingCartManagerGetState = () => ShoppingCartManagerState;

export interface ShoppingCartManager {
	getState: ShoppingCartManagerGetState;
	subscribe: ShoppingCartManagerSubscribe;
	actions: ShoppingCartManagerActions;
	fetchInitialCart: WaitForReady;
}

export type UseShoppingCart = ShoppingCartManagerActions & ShoppingCartManagerState;

export type ReplaceProductInCart = (
	uuidToReplace: string,
	productPropertiesToChange: Partial< RequestCartProduct >
) => Promise< ResponseCart >;

export type ReloadCartFromServer = () => Promise< ResponseCart >;

export type ClearCartMessages = () => Promise< ResponseCart >;

export type ReplaceProductsInCart = (
	products: MinimalRequestCartProduct[]
) => Promise< ResponseCart >;

export type AddProductsToCart = (
	products: MinimalRequestCartProduct[]
) => Promise< ResponseCart >;

export type RemoveCouponFromCart = () => Promise< ResponseCart >;

export type ApplyCouponToCart = ( couponId: string ) => Promise< ResponseCart >;

export type RemoveProductFromCart = ( uuidToRemove: string ) => Promise< ResponseCart >;

export type UpdateTaxLocationInCart = ( location: CartLocation ) => Promise< ResponseCart >;

export type SetCouponFieldVisible = ( couponFieldVisible: boolean ) => void;

export type RemoveCouponAndClearField = () => Promise< ResponseCart< ResponseCartProduct > >;

/**
 * The custom hook keeps a cached version of the server cart, as well as a
 * cache status.
 *
 *   - 'fresh': Page has loaded and no requests have been sent.
 *   - 'fresh-pending': Page has loaded and we are waiting for the initial request.
 *   - 'invalid': Local cart data has been edited.
 *   - 'valid': Local cart has been reloaded from the server.
 *   - 'pending': Request has been sent, awaiting response.
 *   - 'error': Something went wrong.
 */
export type CacheStatus = 'fresh' | 'fresh-pending' | 'valid' | 'invalid' | 'pending' | 'error';

/**
 * Possible states re. coupon submission.
 *
 *   - 'fresh': User has not (yet) attempted to apply a coupon.
 *   - 'pending': Coupon request has been sent, awaiting response.
 *   - 'applied': Coupon has been applied to the cart.
 *   - 'rejected': Coupon code did not apply. The reason should be in the cart errors.
 */
export type CouponStatus = 'fresh' | 'pending' | 'applied' | 'rejected';

export type ShoppingCartAction =
	| { type: 'CLEAR_QUEUED_ACTIONS' }
	| { type: 'CLEAR_MESSAGES' }
	| { type: 'UPDATE_LAST_VALID_CART' }
	| { type: 'REMOVE_CART_ITEM'; uuidToRemove: string }
	| { type: 'CART_PRODUCTS_ADD'; products: RequestCartProduct[] }
	| { type: 'CART_PRODUCTS_REPLACE_ALL'; products: RequestCartProduct[] }
	| { type: 'SET_LOCATION'; location: CartLocation }
	| {
			type: 'CART_PRODUCT_REPLACE';
			uuidToReplace: string;
			productPropertiesToChange: Partial< RequestCartProduct >;
	  }
	| { type: 'ADD_COUPON'; couponToAdd: string }
	| { type: 'REMOVE_COUPON' }
	| { type: 'CART_RELOAD' }
	| { type: 'RECEIVE_INITIAL_RESPONSE_CART'; initialResponseCart: ResponseCart }
	| { type: 'FETCH_INITIAL_RESPONSE_CART' }
	| { type: 'REQUEST_UPDATED_RESPONSE_CART' }
	| { type: 'RECEIVE_UPDATED_RESPONSE_CART'; updatedResponseCart: ResponseCart }
	| { type: 'RAISE_ERROR'; error: ShoppingCartError; message: string };

export interface ShoppingCartManagerActions {
	addProductsToCart: AddProductsToCart;
	removeProductFromCart: RemoveProductFromCart;
	applyCoupon: ApplyCouponToCart;
	removeCoupon: RemoveCouponFromCart;
	updateLocation: UpdateTaxLocationInCart;
	replaceProductInCart: ReplaceProductInCart;
	replaceProductsInCart: ReplaceProductsInCart;
	reloadFromServer: ReloadCartFromServer;
	clearMessages: ClearCartMessages;
}

export type ShoppingCartError = 'GET_SERVER_CART_ERROR' | 'SET_SERVER_CART_ERROR';

export type ShoppingCartState = {
	responseCart: TempResponseCart;
	lastValidResponseCart: ResponseCart;
	couponStatus: CouponStatus;
	queuedActions: ShoppingCartAction[];
} & (
	| {
			cacheStatus: Exclude< CacheStatus, 'error' >;
			loadingError?: undefined;
			loadingErrorType?: undefined;
	  }
	| {
			cacheStatus: 'error';
			loadingError: string;
			loadingErrorType: ShoppingCartError;
	  }
);

export interface WithShoppingCartProps {
	shoppingCartManager: UseShoppingCart;
	cart: ResponseCart;
}

export type CartValidCallback = ( cart: ResponseCart ) => void;

export type DispatchAndWaitForValid = ( action: ShoppingCartAction ) => Promise< ResponseCart >;

export type SavedActionPromise = {
	resolve: ( responseCart: ResponseCart ) => void;
	reject: ( error: CartActionError ) => void;
};

export interface ActionPromises {
	resolve: ( tempResponseCart: TempResponseCart ) => void;
	reject: ( error: CartActionError ) => void;
	add: ( actionPromise: SavedActionPromise ) => void;
}

export interface CartSyncManager {
	syncPendingCartToServer: (
		state: ShoppingCartState,
		dispatch: Dispatch< ShoppingCartAction >
	) => void;
	fetchInitialCartFromServer: ( dispatch: Dispatch< ShoppingCartAction > ) => void;
}

export interface RequestCart {
	blog_id: number;
	cart_key?: CartKey;
	products: RequestCartProduct[];
	tax: RequestCartTaxData;
	coupon: string;
	temporary: false;
}

export type RequestCartTaxData = null | {
	location: {
		country_code: string | undefined;
		postal_code: string | undefined;
		subdivision_code: string | undefined;
		vat_id?: string;
		organization?: string;
		address?: string;
		city?: string;
	};
};

export interface RequestCartProduct {
	product_slug: string;
	product_id?: number;
	meta: string;
	volume: number;
	quantity: number | null;
	extra: RequestCartProductExtra;
}

export type MinimalRequestCartProduct = Partial< RequestCartProduct > &
	Pick< RequestCartProduct, 'product_slug' >;

export interface ResponseCart< P = ResponseCartProduct > {
	blog_id: number;
	cart_key: CartKey;
	products: P[];

	/**
	 * The amount of tax collected.
	 * @deprecated This is a float and is unreliable. Use total_tax_integer.
	 */
	total_tax: string;

	/**
	 * The amount of tax collected in the currency's smallest unit.
	 */
	total_tax_integer: number;

	/**
	 * The amount of tax collected per product.
	 */
	total_tax_breakdown: TaxBreakdownItem[];

	/**
	 * The cart's total cost.
	 * @deprecated This is a float and is unreliable. Use total_cost_integer.
	 */
	total_cost: number;

	/**
	 * The cart's total cost in the currency's smallest unit.
	 */
	total_cost_integer: number;

	/**
	 * The difference between the cost before any coupon and the actual price
	 * for all products in the currency's smallest unit.
	 *
	 * Note that the difference may be caused by many factors, not just coupons.
	 * It's best not to rely on it.
	 */
	coupon_savings_total_integer: number;

	/**
	 * The subtotal with taxes included in the currency's smallest unit.
	 *
	 * This is the sum of each item's price with all discounts (including
	 * coupons), but without taxes. This does not include credits!
	 */
	sub_total_with_taxes_integer: number;

	/**
	 * The subtotal without taxes included in the currency's smallest unit.
	 *
	 * This is the sum of each item's price with all discounts (including
	 * coupons), but without taxes. This does not include credits!
	 */
	sub_total_integer: number;

	/**
	 * The number of credits available in the currency's smallest unit.
	 */
	credits_integer: number;

	/**
	 * Gift Details
	 */
	gift_details?: ResponseCartGiftDetails;

	/**
	 * True if the cart contains a purchase for a different user's site.
	 */
	is_gift_purchase?: boolean;

	currency: string;
	allowed_payment_methods: string[];
	coupon: string;
	is_coupon_applied: boolean;
	has_auto_renew_coupon_been_automatically_applied: boolean;
	locale: string;
	is_signup: boolean;
	messages?: ResponseCartMessages;
	cart_generated_at_timestamp: number;
	tax: ResponseCartTaxData;
	next_domain_is_free: boolean;
	next_domain_condition: '' | 'blog';
	bundled_domain?: string;
	terms_of_service?: TermsOfServiceRecord[];
	has_pending_payment?: boolean;
}

export interface ResponseCartTaxData {
	location: {
		country_code?: string;
		postal_code?: string;
		subdivision_code?: string;
		vat_id?: string;
		organization?: string;
		address?: string;
		city?: string;
	};
	display_taxes: boolean;
}

export interface TaxBreakdownItem {
	tax_collected: number;
	tax_collected_integer: number;
	label?: string;
	rate: number;
	rate_display: string;
}

/**
 * Local schema for response cart that can contain incomplete products. This
 * schema is only used inside the reducer and will only differ from a
 * ResponseCart if the cacheStatus is invalid.
 */
export type TempResponseCart = ResponseCart< RequestCartProduct >;

export interface ResponseCartMessages {
	errors?: ResponseCartMessage[];
	success?: ResponseCartMessage[];
	persistent_errors?: ResponseCartMessage[];
}

export interface ResponseCartMessage {
	code: string;
	message: string;
}

export interface ResponseCartProduct {
	uuid: string;
	product_name: string;
	product_slug: string;
	product_id: number;
	currency: string;

	product_name_en: string;

	/**
	 * The cart item's original price without volume in the currency's smallest unit.
	 *
	 * Discounts and volume are not included, but quantity is included.
	 */
	item_original_cost_integer: number;

	/**
	 * The monthly term original price of a cart item in the currency's smallest unit.
	 */
	item_original_monthly_cost_integer: number;

	/**
	 * The cart item's original price with volume in the currency's smallest unit.
	 *
	 * Discounts are not included, but volume and quantity are included.
	 */
	item_original_subtotal_integer: number;

	/**
	 * The cart item's original price for quantity 1 in the currency's smallest unit.
	 *
	 * Discounts are not included, but volume is included.
	 */
	item_original_cost_for_quantity_one_integer: number;

	/**
	 * The cart item's subtotal in the currency's smallest unit.
	 *
	 * This is the cost of the item with all discounts (including coupons),
	 * but without taxes.
	 */
	item_subtotal_integer: number;

	/**
	 * The cart item's subtotal without volume.
	 * @deprecated This is a float and is unreliable. Use item_subtotal_integer
	 */
	cost: number;

	/**
	 * The amount of the local currency deducted by an applied coupon, if any.
	 * This is in the currency's smallest unit.
	 */
	coupon_savings_integer?: number;

	price_tier_minimum_units?: number | null;
	price_tier_maximum_units?: number | null;

	/**
	 * A cost override is a change to the price of a product. The new price and the old (original) price are both provided.
	 *
	 * The override_code is a string that identifies the reason for the override.
	 * When displaying the reason to the customer, use the human_readable_reason.
	 */
	cost_overrides: ResponseCartCostOverride[];

	/**
	 * If set, is used to transform the usage/quantity of units used to derive the number of units
	 * we want to bill the customer for, before applying the per unit cost.
	 *
	 * To put simply, the purpose of this attribute is to bill the customer at a different granularity compared to their usage.
	 */
	price_tier_transform_quantity_divide_by?: number | null;

	/**
	 * Used for rounding the number of units we want to bill the customer for (which is derived after dividing the
	 * usage/quantity of units by the `price_tier_transform_quantity_divide_by` number).
	 *
	 * Used only when `$this->price_tier_transform_quantity_divide_by` is set. Possible values are: `up`, `down`
	 */
	price_tier_transform_quantity_round?: string | null;
	is_domain_registration: boolean;
	is_bundled: boolean;
	is_sale_coupon_applied: boolean;
	meta: string;
	time_added_to_cart: number;

	/**
	 * The billing term in days in numeric format, but as a string.
	 *
	 * Typically one of '31' (monthly), '365' (annual), or '730' (biennial).
	 *
	 * Similar to `months_per_bill_period`.
	 */
	bill_period: string;

	/**
	 * The billing term in months in numeric format.
	 *
	 * Typically one of 1 (monthly), 12 (annual), or 24 (biennial).
	 *
	 * Similar to `bill_period`.
	 */
	months_per_bill_period: number | null;

	volume: number;
	quantity: number | null;
	current_quantity: number | null;
	extra: ResponseCartProductExtra;
	item_tax: number;
	item_tax_rate?: number;
	product_type: string;
	included_domain_purchase_amount: number;

	/**
	 * True if the product is a renewal.
	 *
	 * This does not get set for `RequestCartProduct` which instead uses
	 * `extra.purchaseType` set to 'renewal'.
	 */
	is_renewal?: boolean;

	/**
	 * True if the product is a renewal and the subscription will auto-renew.
	 *
	 * A subscription will auto-renew if it both can auto-renew (it's a recurring subscription,
	 * has a payment method, isn't blocked, etc.) and the user has auto-renew enabled.
	 */
	is_renewal_and_will_auto_renew?: boolean;

	/**
	 * True if the product will not renew.
	 */
	is_one_time_purchase?: boolean;

	subscription_id?: string;
	introductory_offer_terms?: IntroductoryOfferTerms;

	/**
	 * True if the cart item represents a purchase for a different user's site.
	 */
	is_gift_purchase?: boolean;

	/**
	 * True if cart item is a domain that is included in a 100 Year Plan
	 */
	is_included_for_100yearplan: boolean;

	/**
	 * If set, this is the ID of the payment method attached to the existing
	 * subscription for this product. This will only be set for renewals and
	 * only if the renewal has a payment method attached.
	 */
	stored_details_id?: string;

	product_variants: ResponseCartProductVariant[];
}

export interface ResponseCartProductVariant {
	product_id: number;
	bill_period_in_months: number;
	product_slug: string;
	currency: string;
	price_integer: number;
	price_before_discounts_integer: number;
	introductory_offer_discount_integer: number;
	introductory_offer_terms:
		| Record< string, never >
		| Pick< IntroductoryOfferTerms, 'interval_unit' | 'interval_count' >;
	volume?: number;
}

export interface ResponseCartCostOverride {
	human_readable_reason: string;
	new_subtotal_integer: number;
	old_subtotal_integer: number;
	override_code: string;
	does_override_original_cost: boolean;
	percentage: number;
	first_unit_only: boolean;
}

export type IntroductoryOfferUnit = 'day' | 'week' | 'month' | 'year' | 'indefinite';

export interface IntroductoryOfferTerms {
	/**
	 * True if the introductory offer is active on this product.
	 */
	enabled: boolean;

	/**
	 * The unit that, when combined with `interval_count`, determines how long
	 * the introductory offer disount should be applied.
	 */
	interval_unit: IntroductoryOfferUnit;

	/**
	 * The count that, when combined with `interval_unit`, determines how long
	 * the introductory offer lasts. eg: if `interval_count` is 3 and
	 * `interval_unit` is 'month', the discount lasts for 3 months (but always
	 * ends before the next renewal unless `transition_after_renewal_count` is
	 * set). If the `interval_unit` is 'month' and the product normally renews
	 * yearly, then the first renewal will be based on `interval_count` (eg:
	 * after 3 months) instead.
	 *
	 * Note that we sometimes renew products a 30 days before their expiry
	 * date, so in the above example, we would likely renew at the 2 month mark
	 * instead.
	 */
	interval_count: number;

	/**
	 * If the introductory offer is not active (if `enabled` is false), the
	 * reason will probably be a human-readable reason why (although it may not
	 * exist even then).
	 */
	reason?: string;

	/**
	 * The number of times the introductory offer cost and period will be used
	 * during renewals before using the regular cost and period. If this is 0,
	 * the discount will last just for the initial purchase; otherwise it will
	 * last for additional renewals also.
	 */
	transition_after_renewal_count: number;

	/**
	 * True if the last discounted renewal will subtract the introductory offer
	 * period from the full period when calculating the price. For example: if
	 * you provide a 3 month free trial on a yearly plan, the first renewal
	 * would only cover 9 months (12 – 3 months). This reduced period is also
	 * reflected in the renewal price, as the user will only pay for the 9
	 * months instead of the full year.
	 */
	should_prorate_when_offer_ends: boolean;
}

export interface CartLocation {
	countryCode?: string;
	postalCode?: string;
	subdivisionCode?: string;
	vatId?: string;
	organization?: string;
	address?: string;
	city?: string;
}

export type DomainLegalAgreementUrl = string;
export type DomainLegalAgreementTitle = string;
export type DomainLegalAgreements = Record< DomainLegalAgreementUrl, DomainLegalAgreementTitle >;

export interface ResponseCartProductExtra {
	context?: string;
	source?: string;
	premium?: boolean;
	new_quantity?: number;
	domain_to_bundle?: string;
	email_users?: TitanProductUser[];
	google_apps_users?: GSuiteProductUser[];
	google_apps_registration_data?: DomainContactDetails;
	receipt_for_domain?: number;
	domain_registration_agreement_url?: string;
	legal_agreements?: never[] | DomainLegalAgreements;
	is_gravatar_domain?: boolean;

	/**
	 * Set to 'renewal' if requesting a renewal.
	 *
	 * Often this does not need to be explicitly set because the shopping cart
	 * endpoint will automatically make a requested product into a renewal if the
	 * product is already owned.
	 *
	 * This is not set for `ResponseCartProduct` objects which use `is_renewal`
	 * instead.
	 */
	purchaseType?: string;

	afterPurchaseUrl?: string;
	isJetpackCheckout?: boolean;
	isAkismetSitelessCheckout?: boolean;
	isMarketplaceSitelessCheckout?: boolean;

	/**
	 * Marketplace properties
	 *
	 * These extra properties are always set for marketplace products.
	 * `product_slug` is for identifying the product, and `product_type` is for identifying the type of the product.
	 */
	is_marketplace_product?: boolean;
	product_slug?: string;
	product_type?: 'marketplace_plugin' | 'marketplace_theme' | 'saas_plugin';

	/**
	 * True when:
	 * - the product has variants ( e.g. annual plan vs. monthly plan vs. multi-year plan )
	 * - we only want to show the single product selected by the user
	 * - we want to prevent the user from switching to a variant
	 *
	 * This will hide product variant UI elements in checkout ( line item variant dropdown or variant upsells )
	 */
	hideProductVariants?: boolean;
}

export interface ResponseCartGiftDetails {
	receiver_blog_id: number;
	receiver_blog_slug?: string;
	receiver_blog_url?: string;
}

export interface RequestCartProductExtra extends ResponseCartProductExtra {
	purchaseId?: string;
	isAkismetSitelessCheckout?: boolean;
	isJetpackCheckout?: boolean;
	isMarketplaceSitelessCheckout?: boolean;
	intentId?: number;
	isGiftPurchase?: boolean;
	jetpackSiteSlug?: string;
	jetpackPurchaseToken?: string;
	auth_code?: string;
	privacy_available?: boolean;
	selected_page_titles?: string[];
	site_title?: string;
	signup_flow?: string;
	import_dns_records?: boolean;
	signup?: boolean;
	headstart_theme?: string;
	feature_slug?: string;
	is_hundred_year_domain?: boolean;
	/**
	 * A way to signal intent to the back end when included as an extra with
	 * certain products.
	 *
	 * The only current usage is on Creator plan products that are bought
	 * on flow `/setup/site-migration`. If value `'migrate` is passed the
	 * Atomic DB will be created with UTF-8 encoding, which is a requirement
	 * for Migration Guru, our new tool for handling migrations. This extra
	 * can be removed once all migration flows are using Migration Guru.
	 *
	 */
	hosting_intent?: string;
}

export interface GSuiteProductUser {
	firstname: string;
	lastname: string;
	email: string;
	password: string;
	recoveryEmail?: string;
}

export interface TitanProductUser {
	alternative_email?: string;
	email: string;
	encrypted_password?: string;
	is_admin?: boolean;
	name?: string;
	password?: string;
}

export type DomainContactDetails = {
	firstName?: string;
	lastName?: string;
	organization?: string;
	email?: string;
	phone?: string;
	address1?: string;
	address2?: string;
	city?: string;
	state?: string;
	postalCode?: string;
	countryCode?: string;
	fax?: string;
	vatId?: string;
	extra?: DomainContactDetailsExtra;
};

export type DomainContactDetailsExtra = {
	ca?: CaDomainContactExtraDetails | null;
	uk?: UkDomainContactExtraDetails | null;
	fr?: FrDomainContactExtraDetails | null;
};

export type CaDomainContactExtraDetails = {
	lang?: string;
	legalType?: string;
	ciraAgreementAccepted?: boolean;
};

export type UkDomainContactExtraDetails = {
	registrantType?: string;
	registrationNumber?: string;
	tradingName?: string;
};

export type FrDomainContactExtraDetails = {
	registrantType?: string;
	registrantVatId?: string;
	trademarkNumber?: string;
	sirenSiret?: string;
};

export interface TermsOfServiceRecord {
	key: string;
	code: string;
	args?: TermsOfServiceRecordArgsBase | TermsOfServiceRecordArgsRenewal;
}

export interface TermsOfServiceRecordArgsBase {
	/**
	 * The date that the subscription will begin, formatted as a ISO 8601 date
	 * (eg: `2004-02-12T15:19:21+00:00`).
	 */
	subscription_start_date: string;

	/**
	 * The `meta` value of the product (eg: its domain name). May be an empty
	 * string if there is no meta.
	 */
	product_meta: string;

	/**
	 * The human readable name of the product.
	 */
	product_name: string;

	/**
	 * The store product ID.
	 */
	product_id: number;

	/**
	 * The price of the next renewal of this product. This may be based on the
	 * product's billing term (eg: in two years for a biennial plan) or the
	 * billing term of the introductory offer, if it differs (eg: in 3 months for
	 * a 3 month free trial of an annual plan).
	 *
	 * If an introductory offer applies for more than one renewal, this will be
	 * the price of the next renewal only, NOT the price of the renewal after the
	 * offer ends!
	 *
	 * This price is locale-formatted with a currency symbol.
	 * @deprecated use renewal_price_integer and format manually
	 */
	renewal_price: string;

	/**
	 * The price of the next renewal of this product. This may be based on the
	 * product's billing term (eg: in two years for a biennial plan) or the
	 * billing term of the introductory offer, if it differs (eg: in 3 months for
	 * a 3 month free trial of an annual plan).
	 *
	 * If an introductory offer applies for more than one renewal, this will be
	 * the price of the next renewal only, NOT the price of the renewal after the
	 * offer ends!
	 *
	 * This price is an integer in the currency's smallest unit.
	 */
	renewal_price_integer: number;

	/**
	 * The price of the product after the promotional pricing expires. If the
	 * next auto-renewal after the price expires would prorate the renewal price,
	 * this DOES NOT include that proration. See
	 * `maybe_prorated_regular_renewal_price_integer` for the price with that proration
	 * included.
	 *
	 * This price is locale-formatted with a currency symbol.
	 * @deprecated use regular_renewal_price_integer and format manually
	 */
	regular_renewal_price: string;

	/**
	 * The price of the product after the promotional pricing expires. If the
	 * next auto-renewal after the price expires would prorate the renewal price,
	 * this DOES NOT include that proration. See
	 * `maybe_prorated_regular_renewal_price_integer` for the price with that proration
	 * included.
	 *
	 * This price is an integer in the currency's smallest unit.
	 */
	regular_renewal_price_integer: number;

	/**
	 * The price of the product for the renewal immediately after the promotional
	 * pricing expires. If the next auto-renewal after the price expires would
	 * prorate the renewal price, this DOES include that proration. See
	 * `regular_renewal_price_integer` for the price without that proration
	 * included.
	 *
	 * This is the price that we will attempt to charge on
	 * `subscription_maybe_prorated_regular_auto_renew_date`.
	 *
	 * This price is an integer in the currency's smallest unit.
	 */
	maybe_prorated_regular_renewal_price_integer: number;

	/**
	 * True if the product in the cart which has these terms is a manual renewal
	 * (as opposed to a new purchase or a quantity upgrade).
	 */
	is_renewal: boolean;

	/**
	 * The number of auto-renewals after the current purchase completes which
	 * will be affected by the promotional pricing. If the product is affected by
	 * a prorated introductory offer, then the auto-renewal where the user will
	 * be charged the prorated price is not counted by this number.
	 */
	remaining_promotional_auto_renewals: number;
}

export interface TermsOfServiceRecordArgsRenewal extends TermsOfServiceRecordArgsBase {
	/**
	 * The date that the promotional pricing will end, formatted as a ISO 8601
	 * date (eg: `2004-02-12T15:19:21+00:00`). This may be the date that an
	 * auto-renew will be attempted with the non-promotional price, but if the
	 * subscription renews earlier than the expiry date, the renewal may happen
	 * earlier than this date. See `subscription_regular_auto_renew_date` for
	 * the actual date of the non-promotional renewal.
	 *
	 * Only set if we can easily determine when the product will renew. Does not
	 * apply to domain transfers or multi-year domains.
	 */
	subscription_end_of_promotion_date: string;

	/**
	 * This date that an auto-renew will be attempted with the non-promotional
	 * possibly prorated price (`maybe_prorated_regular_renewal_price_integer`).
	 *
	 * This is ISO 8601 formatted (eg: `2004-02-12T15:19:21+00:00`).
	 *
	 * Only set if we can easily determine when the product will renew. Does not
	 * apply to domain transfers or multi-year domains.
	 */
	subscription_maybe_prorated_regular_auto_renew_date: string;

	/**
	 * This date that an auto-renew will be attempted with the non-promotional
	 * regular recurring price (`regular_renewal_price_integer`).
	 *
	 * This is ISO 8601 formatted (eg: `2004-02-12T15:19:21+00:00`).
	 *
	 * Only set if we can easily determine when the product will renew. Does not
	 * apply to domain transfers or multi-year domains.
	 */
	subscription_regular_auto_renew_date: string;

	/**
	 * The date when the product's subscription will expire if not renewed. This
	 * might be its renewal date, but it might not be since we often renew
	 * products earlier than their expiry date.
	 *
	 * This is ISO 8601 formatted (eg: `2004-02-12T15:19:21+00:00`).
	 *
	 * Only set if we can easily determine when the product will renew. Does not
	 * apply to domain transfers or multi-year domains.
	 */
	subscription_expiry_date: string;

	/**
	 * The date when the product's subscription will next automatically attempt a
	 * renewal. Note that this may not be the end of the promotional price, since
	 * some promotions apply to renewals also.
	 *
	 * This is ISO 8601 formatted (eg: `2004-02-12T15:19:21+00:00`).
	 *
	 * Only set if we can easily determine when the product will renew. Does not
	 * apply to domain transfers or multi-year domains.
	 */
	subscription_auto_renew_date: string;

	/**
	 * The number of days before the renewal attempt when the user will receive a
	 * pre-renewal reminder email.
	 *
	 * Only set if we can easily determine when the product will renew. Does not
	 * apply to domain transfers or multi-year domains.
	 */
	subscription_pre_renew_reminder_days: number;

	/**
	 * The number of pre-renewal emails the user will receive.
	 *
	 * Typically this is 1 or 0. For example, monthly subscriptions don't usually
	 * get a pre-renewal email.
	 *
	 * Only set if we can easily determine when the product will renew. Does not
	 * apply to domain transfers or multi-year domains.
	 */
	subscription_pre_renew_reminders_count: number;
}
