import { initializePaddle, type Paddle } from "@paddle/paddle-js";

let cached: Promise<Paddle | undefined> | null = null;

/* One Paddle instance for the app. The token and environment are baked into the
 * build (NEXT_PUBLIC_*), never fetched, so a production build can never load a
 * sandbox token by accident. */
export function initPaddle(): Promise<Paddle | undefined> {
    if (!cached) {
        cached = initializePaddle({
            environment:
                (process.env.NEXT_PUBLIC_PADDLE_ENV as "sandbox" | "production") ?? "sandbox",
            token: process.env.NEXT_PUBLIC_PADDLE_CLIENT_TOKEN ?? "",
        });
    }
    return cached;
}

export interface PricedLine {
    priceId: string;
    /* Already localised and currency-formatted by Paddle, e.g. "£39.00". The line
     * total for the quantity, not the unit price. */
    total: string;
    unit: string;
}

export interface PricePreview {
    currency: string;
    /* Grand total, formatted. */
    total: string;
    lines: Record<string, PricedLine>;
}

/*
 * previewPrices asks Paddle for the real localised prices of a set of line items,
 * so the order summary shows what the customer will actually pay rather than a
 * hardcoded number that would drift from the dashboard.
 *
 * It returns null when Paddle is unavailable or a price cannot be previewed (an
 * unconfigured sandbox price, an ad blocker). The caller falls back to showing
 * the line items without amounts rather than a wrong total — the real figure
 * still appears in the checkout overlay, which is the authority.
 */
export async function previewPrices(
    items: { priceId: string; quantity: number }[],
): Promise<PricePreview | null> {
    if (items.length === 0) return { currency: "", total: "", lines: {} };
    const paddle = await initPaddle();
    if (!paddle) return null;
    try {
        const res = await paddle.PricePreview({
            items: items.map((i) => ({ priceId: i.priceId, quantity: i.quantity })),
        });
        const currency = res.data.currencyCode;
        const lines: Record<string, PricedLine> = {};
        // Paddle gives per-line totals but no grand total, so sum the raw minor
        // units and format once. The checkout overlay is the authority; this is
        // the honest preview beside it.
        let subtotalMinor = 0;
        for (const li of res.data.details.lineItems) {
            lines[li.price.id] = {
                priceId: li.price.id,
                total: li.formattedTotals.subtotal,
                unit: li.formattedUnitTotals.subtotal,
            };
            subtotalMinor += Number.parseInt(li.totals.subtotal, 10) || 0;
        }
        const total = new Intl.NumberFormat(undefined, {
            style: "currency",
            currency,
        }).format(subtotalMinor / 100);
        return { currency, total, lines };
    } catch {
        return null;
    }
}
