//
//  offer-formatting.ts
//  AppStoreKit
//
//  Created by Dersu Abolfathi on 8/8/19.
//  Copyright (c) 2019 Apple Inc. All rights reserved.
//
import { isNothing } from "@jet/environment";
import * as serverData from "../../foundation/json-parsing/server-data";
export class SubscriptionRecurrence {
    constructor(periodDuration, periodCount, type) {
        this.periodDuration = periodDuration;
        this.periodCount = periodCount;
        this.type = type;
    }
    isEqualTo(otherRecurrence) {
        return (otherRecurrence.periodDuration === this.periodDuration &&
            otherRecurrence.periodCount === this.periodCount &&
            otherRecurrence.type === this.type);
    }
}
const DAYS_PER_WEEK = 7;
/**
 * Determines the recurrence type for the server-vended subscription recurrence string.
 * @param serverRecurrence The string denoting the recurring subscription recurrence (i.e. 'P1M', 'P1Y', etc.).
 * @param numberOfPeriods - The number of periods for the subscription.
 * @returns {SubscriptionRecurrence} The recurrence value.
 */
export function subscriptionRecurrenceForServerRecurrence(objectGraph, serverRecurrence, numberOfPeriods) {
    if (isNothing(serverRecurrence)) {
        return null;
    }
    const match = serverRecurrence.match(/P(\d+)([A-Z]+)/);
    if (!match || match.length !== 3) {
        return null;
    }
    let periodDuration = serverData.asNumber(match[1]);
    let type = match[2];
    if (!periodDuration || !type) {
        return null;
    }
    // Unfortunately, the server will give us weekly recurrences in days. So, we need to transform a days-based
    // recurrence that lands on week boundaries to a week-based recurrence.
    if (type === "D" && periodDuration > 0 && periodDuration % DAYS_PER_WEEK === 0) {
        type = "W";
        periodDuration = periodDuration / DAYS_PER_WEEK;
    }
    return new SubscriptionRecurrence(periodDuration, numberOfPeriods !== null && numberOfPeriods !== void 0 ? numberOfPeriods : 1, type);
}
// endregion
// region IAP Subscription Trials
/**
 * The pre-install description for a subscription trial offer.
 * @param inAppOfferData The overall data for the subscription, including the discount.
 * @returns {string} The fully-localized formatted string for the subscription trial description.
 */
export function installPagePreInstallTrialDescription(objectGraph, inAppOfferData) {
    const discountData = serverData.asArrayOrEmpty(inAppOfferData, "discounts")[0];
    if (!discountData) {
        return null;
    }
    const trialRecurrencePeriod = serverData.asString(discountData, "recurringSubscriptionPeriod");
    const trialNumberOfPeriods = serverData.asNumber(discountData, "numOfPeriods");
    const postTrialRecurrencePeriod = serverData.asString(inAppOfferData, "recurringSubscriptionPeriod");
    const postTrialNumberOfPeriods = serverData.asNumber(inAppOfferData, "numOfPeriods");
    if (!trialRecurrencePeriod || !postTrialRecurrencePeriod) {
        return null;
    }
    const trialType = serverData.asString(discountData, "modeType");
    const trialRecurrence = subscriptionRecurrenceForServerRecurrence(objectGraph, trialRecurrencePeriod, trialNumberOfPeriods);
    const postTrialRecurrence = subscriptionRecurrenceForServerRecurrence(objectGraph, postTrialRecurrencePeriod, postTrialNumberOfPeriods);
    // Replace any spaces within the formatted prices with non-breaking spaces to avoid prices breaking across multiple lines
    const trialPriceFormatted = serverData.asString(discountData, "priceFormatted").replace(/ /g, "\u00a0");
    const postTrialPriceFormatted = serverData.asString(inAppOfferData, "priceFormatted").replace(/ /g, "\u00a0");
    let postTrialPriceDuration = priceDurationString(objectGraph, postTrialRecurrence.type, postTrialRecurrence.periodDuration, postTrialPriceFormatted);
    // Update any slash (/) characters to be non-breaking by wrapping with u2060 word-joiner unicode characters.
    postTrialPriceDuration = postTrialPriceDuration.replace(/\//g, "\u2060/\u2060");
    switch (trialType) {
        case "FreeTrial":
            // template: "Free for @@durationCount@@, then @@postTrialPriceDuration@@ after trial."
            // result: "Free for 6 months, then $4.99/month after trial."
            const freeTrialDurationCount = durationCountString(objectGraph, trialRecurrence.type, trialRecurrence.periodDuration * trialRecurrence.periodCount);
            if (freeTrialDurationCount && postTrialPriceDuration) {
                return objectGraph.loc
                    .string("InAppOfferPage.Description.FreeTrialTemplate")
                    .replace("@@durationCount@@", tokenReplacer(freeTrialDurationCount))
                    .replace("@@postTrialPriceDuration@@", tokenReplacer(postTrialPriceDuration));
            }
            break;
        case "PayUpFront":
            //  template: "@@durationCount@@ for @@trialPrice@@, then @@postTrialPriceDuration@@ after trial."
            //  result: "3 months for $9.99, then $19.99/year after trial."
            const payUpFrontDurationCount = durationCountString(objectGraph, trialRecurrence.type, trialRecurrence.periodDuration * trialRecurrence.periodCount);
            if (payUpFrontDurationCount && postTrialPriceDuration) {
                return objectGraph.loc
                    .string("InAppOfferPage.Description.PaidUpFrontTemplate")
                    .replace("@@durationCount@@", tokenReplacer(payUpFrontDurationCount))
                    .replace("@@trialPrice@@", tokenReplacer(trialPriceFormatted))
                    .replace("@@postTrialPriceDuration@@", tokenReplacer(postTrialPriceDuration));
            }
            break;
        case "PayAsYouGo":
            // template: "@@trialPriceDuration@@ for @@durationCount@@, then @@postTrialPriceDuration@@ after trial."
            // result: "$1.99/week for 3 weeks, then $9.99/month after trial."
            const trialPriceDuration = priceDurationString(objectGraph, trialRecurrence.type, trialRecurrence.periodDuration, trialPriceFormatted);
            const durationCount = durationCountString(objectGraph, trialRecurrence.type, trialRecurrence.periodDuration * trialRecurrence.periodCount);
            if (durationCount && postTrialPriceDuration) {
                return objectGraph.loc
                    .string("InAppOfferPage.Description.PaidTrialTemplate")
                    .replace("@@trialPriceDuration@@", tokenReplacer(trialPriceDuration))
                    .replace("@@durationCount@@", tokenReplacer(durationCount))
                    .replace("@@postTrialPriceDuration@@", tokenReplacer(postTrialPriceDuration));
            }
            break;
        default:
            return null;
    }
    return null;
}
// <rdar://problem/55389195> Arcade grouping upsell text showing pricing token
// We use a function replacer instead of a string replacer, since `$` is interpreted as a special substitution token.
// Function replacers have less special semantics.
function tokenReplacer(replacementString) {
    return replacementString;
}
/**
 * Returns a string representing a formatted price per duration of time.
 * e.g. "$3.99/day" if the recurrenceType is `days` and durationCount is `1`.
 * e.g. "$3.99 every 3 months" the recurrenceType is `months` and durationCount is `3`.
 * @param recurrenceType: The recurrence type - e.g. days, weeks, months, years.
 * @param durationCount The count of the duration that will be represented in the string.
 * @param formattedPrice The formatted price that will be substituted in the returned string.
 * @returns {string} The localized string for the price per duration.
 */
export function priceDurationString(objectGraph, recurrenceType, durationCount, formattedPrice) {
    // template: "@@price@@ every @@count@@ days"
    // result: "$1.99 every 3 days"
    let template;
    switch (recurrenceType) {
        // NOTE: Below we have added a workaround to enforce use of the .one plural string variation when count is exactly 1, as jet localizer doesn't do this by default for all languages.
        // In rdar://113586253 we will adopt newer API from jet that allows us to do this globally, and then this workaround can be removed.
        case "D":
            if (durationCount === 1) {
                template = objectGraph.loc
                    .string("InAppOfferPage.Description.PriceDuration.Days.one")
                    .replace("@@count@@", objectGraph.loc.formattedCount(durationCount));
            }
            else {
                template = objectGraph.loc.stringWithCount("InAppOfferPage.Description.PriceDuration.Days", durationCount);
            }
            break;
        case "W":
            if (durationCount === 1) {
                template = objectGraph.loc
                    .string("InAppOfferPage.Description.PriceDuration.Weeks.one")
                    .replace("@@count@@", objectGraph.loc.formattedCount(durationCount));
            }
            else {
                template = objectGraph.loc.stringWithCount("InAppOfferPage.Description.PriceDuration.Weeks", durationCount);
            }
            break;
        case "M":
            if (durationCount === 1) {
                template = objectGraph.loc
                    .string("InAppOfferPage.Description.PriceDuration.Months.one")
                    .replace("@@count@@", objectGraph.loc.formattedCount(durationCount));
            }
            else {
                template = objectGraph.loc.stringWithCount("InAppOfferPage.Description.PriceDuration.Months", durationCount);
            }
            break;
        case "Y":
            if (durationCount === 1) {
                template = objectGraph.loc
                    .string("InAppOfferPage.Description.PriceDuration.Years.one")
                    .replace("@@count@@", objectGraph.loc.formattedCount(durationCount));
            }
            else {
                template = objectGraph.loc.stringWithCount("InAppOfferPage.Description.PriceDuration.Years", durationCount);
            }
            break;
        default:
            break;
    }
    return template.replace("@@price@@", tokenReplacer(formattedPrice));
}
/**
 * Returns a string representing the duration count of the specified recurrence type.
 * e.g. "3 days" if recurrenceType is `days` and durationCount is `3`.
 * @param recurrenceType: The recurrence type - e.g. days, weeks, months, years.
 * @param durationCount The count of the duration that will be represented in the string.
 * @returns {string} The localized duration count string.
 */
export function durationCountString(objectGraph, recurrenceType, durationCount) {
    switch (recurrenceType) {
        // NOTE: Below we have added a workaround to enforce use of the .one plural string variation when count is exactly 1, as jet localizer doesn't do this by default for all languages.
        // In rdar://113586253 we will adopt newer API from jet that allows us to do this globally, and then this workaround can be removed.
        case "D":
            if (durationCount === 1) {
                return objectGraph.loc
                    .string("InAppOfferPage.Description.DurationCount.Days.one")
                    .replace("@@count@@", objectGraph.loc.formattedCount(durationCount));
            }
            return objectGraph.loc.stringWithCount("InAppOfferPage.Description.DurationCount.Days", durationCount);
        case "W":
            if (durationCount === 1) {
                return objectGraph.loc
                    .string("InAppOfferPage.Description.DurationCount.Weeks.one")
                    .replace("@@count@@", objectGraph.loc.formattedCount(durationCount));
            }
            return objectGraph.loc.stringWithCount("InAppOfferPage.Description.DurationCount.Weeks", durationCount);
        case "M":
            if (durationCount === 1) {
                return objectGraph.loc
                    .string("InAppOfferPage.Description.DurationCount.Months.one")
                    .replace("@@count@@", objectGraph.loc.formattedCount(durationCount));
            }
            return objectGraph.loc.stringWithCount("InAppOfferPage.Description.DurationCount.Months", durationCount);
        case "Y":
            if (durationCount === 1) {
                return objectGraph.loc
                    .string("InAppOfferPage.Description.DurationCount.Years.one")
                    .replace("@@count@@", objectGraph.loc.formattedCount(durationCount));
            }
            return objectGraph.loc.stringWithCount("InAppOfferPage.Description.DurationCount.Years", durationCount);
        default:
            break;
    }
    return null;
}
//# sourceMappingURL=offer-formatting.js.map