import { Resource } from "../resource.js";
import { logger } from "../util/logger.js";
import { createStripeClient, handleStripeDeleteError } from "./client.js";
/**
 * Create and manage Stripe prices for products
 *
 * @example
 * // Create a one-time fixed price for a product
 * const oneTimePrice = await Price("basic-license", {
 *   currency: "usd",
 *   unitAmount: 2999, // $29.99
 *   product: "prod_xyz"
 * });
 *
 * @example
 * // Create a recurring subscription price with fixed monthly billing
 * const subscriptionPrice = await Price("pro-monthly", {
 *   currency: "usd",
 *   unitAmount: 1499, // $14.99/month
 *   product: "prod_xyz",
 *   recurring: {
 *     interval: "month",
 *     usageType: "licensed"
 *   }
 * });
 *
 * @example
 * // Create a graduated tiered price with usage-based billing
 * const tieredPrice = await Price("api-usage", {
 *   currency: "usd",
 *   product: "prod_xyz",
 *   billingScheme: "tiered",
 *   tiersMode: "graduated",
 *   recurring: {
 *     interval: "month",
 *     usageType: "metered"
 *   },
 *   tiers: [
 *     {
 *       upTo: 10000,
 *       unitAmount: 0 // First 10k API calls free
 *     },
 *     {
 *       upTo: 50000,
 *       unitAmount: 2 // $0.02 per call up to 50k
 *     },
 *     {
 *       upTo: "inf",
 *       unitAmount: 1 // $0.01 per call beyond 50k
 *     }
 *   ]
 * });
 *
 * @example
 * // Create a volume-based tiered price with overage cap
 * const volumePrice = await Price("storage", {
 *   currency: "usd",
 *   product: "prod_xyz",
 *   billingScheme: "tiered",
 *   tiersMode: "volume",
 *   recurring: {
 *     interval: "month"
 *   },
 *   tiers: [
 *     {
 *       upTo: 100,
 *       unitAmount: 500 // $5 per GB for up to 100GB
 *     },
 *     {
 *       upTo: 1000,
 *       unitAmount: 400 // $4 per GB for 101-1000GB
 *     },
 *     {
 *       upTo: "inf",
 *       flatAmount: 300000 // Cap at $3000 for unlimited storage
 *     }
 *   ]
 * });
 *
 * @example
 * // Create a metered price with billing meter for API usage tracking
 * const meteredPrice = await Price("api-usage-price", {
 *   product: "prod_xyz",
 *   currency: "usd",
 *   billingScheme: "tiered",
 *   tiersMode: "graduated",
 *   recurring: {
 *     interval: "month",
 *     usageType: "metered",
 *     meter: "meter_123abc" // Associate with billing meter
 *   },
 *   tiers: [
 *     { upTo: 10000, unitAmountDecimal: "0" },
 *     { upTo: 25000, unitAmountDecimal: "0.002" },
 *     { upTo: "inf", flatAmountDecimal: "3000" }
 *   ]
 * });
 */
export const Price = Resource("stripe::Price", async function (_id, props) {
    const adopt = props.adopt ?? this.scope.adopt;
    const stripe = await createStripeClient({ apiKey: props.apiKey });
    if (this.phase === "delete") {
        try {
            if (this.phase === "delete" && this.output?.id) {
                // Prices can't be deleted, only deactivated
                await stripe.prices.update(this.output.id, { active: false });
            }
        }
        catch (error) {
            handleStripeDeleteError(error, "Price", this.output?.id);
        }
        return this.destroy();
    }
    // Validate tier-related constraints
    if (props.tiers && props.billingScheme !== "tiered") {
        throw new Error("Tiers can only be used with billingScheme: 'tiered'");
    }
    if (props.tiers && (props.unitAmount || props.unitAmountDecimal)) {
        throw new Error("Cannot set both tiers and unitAmount/unitAmountDecimal");
    }
    if (props.tiersMode && !props.tiers) {
        throw new Error("tiersMode requires tiers to be defined");
    }
    try {
        let price;
        if (this.phase === "update" && this.output?.id) {
            // Update existing price (limited properties can be updated)
            const updateParams = {
                active: props.active,
                metadata: props.metadata,
                nickname: props.nickname,
                lookup_key: props.lookupKey,
                transfer_lookup_key: props.transferLookupKey,
                expand: ["tiers"],
            };
            // Note: Stripe doesn't allow updating recurring fields (including meter) after price creation
            // If meter needs to be changed, a new price must be created
            price = await stripe.prices.update(this.output.id, updateParams);
        }
        else {
            // Create new price
            const createParams = {
                currency: props.currency,
                product: props.product,
                active: props.active,
                billing_scheme: props.billingScheme,
                nickname: props.nickname,
                metadata: props.metadata,
                tax_behavior: props.taxBehavior,
                lookup_key: props.lookupKey,
                transfer_lookup_key: props.transferLookupKey,
                expand: ["tiers"],
            };
            // Add unit amount fields
            if (props.unitAmount !== undefined) {
                createParams.unit_amount = props.unitAmount;
            }
            else if (props.unitAmountDecimal !== undefined) {
                createParams.unit_amount_decimal = props.unitAmountDecimal;
            }
            // Add recurring parameters if present
            if (props.recurring) {
                createParams.recurring = {
                    interval: props.recurring.interval,
                    interval_count: props.recurring.intervalCount,
                    usage_type: props.recurring.usageType,
                };
                // Add meter to recurring if present (only for metered usage type)
                if (props.recurring.usageType === "metered" &&
                    props.recurring.meter) {
                    createParams.recurring.meter =
                        typeof props.recurring.meter === "string"
                            ? props.recurring.meter
                            : props.recurring.meter.id;
                }
            }
            // Add tier configuration if present
            if (props.tiers) {
                createParams.tiers = props.tiers.map((tier) => ({
                    up_to: tier.upTo === "inf" ? "inf" : tier.upTo,
                    flat_amount: tier.flatAmount,
                    flat_amount_decimal: tier.flatAmountDecimal,
                    unit_amount: tier.unitAmount,
                    unit_amount_decimal: tier.unitAmountDecimal,
                }));
            }
            if (props.tiersMode) {
                createParams.tiers_mode = props.tiersMode;
            }
            // Add transform quantity if present
            if (props.transformQuantity) {
                createParams.transform_quantity = {
                    divide_by: props.transformQuantity.divideBy,
                    round: props.transformQuantity.round,
                };
            }
            if (props.lookupKey) {
                const existingPrices = await stripe.prices.list({
                    lookup_keys: [props.lookupKey],
                    limit: 1,
                });
                if (existingPrices.data.length > 0) {
                    if (adopt) {
                        const existingPrice = existingPrices.data[0];
                        const updateParams = {
                            active: props.active,
                            metadata: props.metadata,
                            nickname: props.nickname,
                            lookup_key: props.lookupKey,
                            transfer_lookup_key: props.transferLookupKey,
                            expand: ["tiers"],
                        };
                        price = await stripe.prices.update(existingPrice.id, updateParams);
                    }
                    else {
                        // Need to retrieve with expanded tiers
                        price = await stripe.prices.retrieve(existingPrices.data[0].id, {
                            expand: ["tiers"],
                        });
                    }
                }
                else {
                    price = await stripe.prices.create(createParams);
                }
            }
            else {
                price = await stripe.prices.create(createParams);
            }
        }
        // Transform Stripe recurring object to our format
        const recurring = price.recurring
            ? {
                interval: price.recurring
                    .interval,
                intervalCount: price.recurring.interval_count,
                usageType: price.recurring
                    .usage_type,
                meter: price.recurring.meter,
            }
            : undefined;
        // Transform Stripe tiers array to our format
        const tiers = price.tiers
            ? price.tiers.map((tier) => ({
                flatAmount: tier.flat_amount || undefined,
                flatAmountDecimal: tier.flat_amount_decimal || undefined,
                unitAmount: tier.unit_amount || undefined,
                unitAmountDecimal: tier.unit_amount_decimal || undefined,
                upTo: tier.up_to === null ? "inf" : tier.up_to,
            }))
            : undefined;
        // Transform transform_quantity if present
        const transformQuantity = price.transform_quantity
            ? {
                divideBy: price.transform_quantity.divide_by,
                round: price.transform_quantity.round,
            }
            : undefined;
        // Map Stripe API response to our output format
        return {
            id: price.id,
            product: typeof price.product === "string" ? price.product : price.product.id,
            currency: price.currency,
            unitAmount: price.unit_amount || undefined,
            unitAmountDecimal: price.unit_amount_decimal || undefined,
            active: price.active,
            billingScheme: price.billing_scheme,
            nickname: price.nickname || undefined,
            recurring: recurring,
            metadata: price.metadata || undefined,
            taxBehavior: price.tax_behavior,
            createdAt: price.created,
            livemode: price.livemode,
            type: price.type,
            lookupKey: price.lookup_key || undefined,
            tiers: tiers,
            tiersMode: price.tiers_mode ?? undefined,
            transformQuantity: transformQuantity,
        };
    }
    catch (error) {
        logger.error("Error creating/updating price:", error);
        throw error;
    }
});
//# sourceMappingURL=price.js.map