/* Single source of truth for the eleva-speed pricing tiers.

   Phase 6 will consume this file to look up Stripe price IDs at runtime
   (from env vars STRIPE_PRICE_*_MONTHLY / *_YEARLY populated by the
   stripe-bootstrap script). For now (Phase 1+catalog-only), this file
   is read by scripts/stripe-bootstrap.ts to create the Stripe Products
   and Prices in the sandbox.

   Multi-currency: each plan exposes a `prices` map keyed by `Currency`
   (eur / usd / gbp / jpy / cad), amounts in MAJOR units. Stripe wants
   minor units — convert at the call site via `toMinorUnits()` (handles
   zero-decimal currencies like JPY correctly).

   Source: docs/pricing/pricing-proposal.md § Multi-devise + docs/superpowers/specs/2026-05-25-org-roles-stripe-billing-design.md §6.1 */

import type { Currency } from "@/lib/billing/currency";
import type { Plan as DbPlan } from "@/lib/db/schema";

export type { Plan, BillingInterval } from "@/lib/db/schema";

export type BillablePlan = "starter" | "pro" | "business";

/* Per-currency price grid. Amounts in MAJOR units (e.g. 19 = €19.00;
   for JPY 2900 = ¥2,900 since JPY is zero-decimal). */
export type CurrencyPrices = Record<Currency, { month: number; year: number }>;

export type PlanPricing = {
  /* Display name (used as Stripe Product name). */
  name: string;
  /* Short marketing description (used as Stripe Product description). */
  description: string;
  /* Major-unit prices per supported currency. Convert to Stripe minor
     units via toMinorUnits(amount, currency). */
  prices: CurrencyPrices;
  /* Soft quotas enforced app-side in Phase 5 (not enforced here). */
  limits: {
    testsPerMonth: number;
    sites: number;
    seats: number;
    retentionDays: number;
  };
  /* Stripe Price IDs (read from env at module load). Undefined when the
     corresponding STRIPE_PRICE_* env var is not set (e.g. dev before
     stripe-bootstrap ran). createCheckoutSession() throws on undefined. */
  stripePriceIds: { month: string | undefined; year: string | undefined };
};

export const BILLABLE_PLANS: Record<BillablePlan, PlanPricing> = {
  starter: {
    name: "Starter",
    description:
      "1 site, hourly monitoring from 3 locations, 100 on-demand tests / month, alerts email + webhook.",
    prices: {
      eur: { month: 19, year: 190 },
      usd: { month: 19, year: 190 },
      gbp: { month: 15, year: 150 },
      jpy: { month: 2900, year: 29000 },
      cad: { month: 28, year: 280 },
    },
    limits: { testsPerMonth: 100, sites: 3, seats: 1, retentionDays: 30 },
    stripePriceIds: {
      month: process.env.STRIPE_PRICE_STARTER_MONTHLY,
      year: process.env.STRIPE_PRICE_STARTER_YEARLY,
    },
  },
  pro: {
    name: "Pro",
    description:
      "15 sites, hourly monitoring from 6 locations, 500 tests / month, Slack + PagerDuty alerts, performance budgets, CI integration.",
    prices: {
      eur: { month: 49, year: 490 },
      usd: { month: 49, year: 490 },
      gbp: { month: 39, year: 390 },
      jpy: { month: 7500, year: 75000 },
      cad: { month: 69, year: 690 },
    },
    limits: { testsPerMonth: 500, sites: 15, seats: 3, retentionDays: 180 },
    stripePriceIds: {
      month: process.env.STRIPE_PRICE_PRO_MONTHLY,
      year: process.env.STRIPE_PRICE_PRO_YEARLY,
    },
  },
  business: {
    name: "Business",
    description:
      "50 sites, hourly monitoring from 8 locations, 2000 tests / month, white-label PDF reports, RBAC, priority support.",
    prices: {
      eur: { month: 149, year: 1490 },
      usd: { month: 149, year: 1490 },
      gbp: { month: 125, year: 1250 },
      jpy: { month: 22000, year: 220000 },
      cad: { month: 199, year: 1990 },
    },
    limits: { testsPerMonth: 2000, sites: 50, seats: 10, retentionDays: 365 },
    stripePriceIds: {
      month: process.env.STRIPE_PRICE_BUSINESS_MONTHLY,
      year: process.env.STRIPE_PRICE_BUSINESS_YEARLY,
    },
  },
};

/* Optional per-seat add-on. One Stripe Product with month + year Prices
   per supported currency. Consumed at checkout when an org orders
   `extra_seats > 0` (see es_org_subscription.extra_seats). */
export const SEAT_ADDON = {
  name: "Extra Seat",
  description: "One additional team member beyond your plan's included seats.",
  prices: {
    eur: { month: 9, year: 90 },
    usd: { month: 9, year: 90 },
    gbp: { month: 7, year: 70 },
    jpy: { month: 1400, year: 14000 },
    cad: { month: 13, year: 130 },
  },
  stripePriceIds: {
    month: process.env.STRIPE_PRICE_SEAT_MONTHLY,
    year: process.env.STRIPE_PRICE_SEAT_YEARLY,
  },
} as const;

/* Free plan limits — no Stripe Product. */
export const FREE_LIMITS = {
  testsPerMonth: 15,
  sites: 1,
  seats: 1,
  retentionDays: 7,
} as const;

/* Metadata tag stored on every Stripe Product + Price we own. Used by the
   bootstrap script to find existing entries and avoid duplicates. */
export const STRIPE_METADATA_APP = "eleva-speed";

/* Currencies that have no fractional unit (Stripe expects integer
   amounts, NOT amount × 100). Keep in sync with currency.ts'
   `zeroDecimal: true` entries. */
const ZERO_DECIMAL_CURRENCIES = new Set<Currency>(["jpy"]);

/* Convert a MAJOR-unit amount (e.g. 19 €, 2900 ¥) to the MINOR units
   Stripe expects per currency:
     - eur / usd / gbp / cad: × 100 (cents)
     - jpy: pass-through (zero-decimal — Stripe wants 2900 for ¥2,900) */
export function toMinorUnits(amount: number, currency: Currency): number {
  if (ZERO_DECIMAL_CURRENCIES.has(currency)) return Math.round(amount);
  return Math.round(amount * 100);
}

/* @deprecated Prefer `toMinorUnits(amount, "eur")`. Kept as a thin alias
   for backwards compat with scripts/stripe-bootstrap.ts. */
export function eurToCents(eur: number): number {
  return toMinorUnits(eur, "eur");
}

export type QuotaLimits = {
  testsPerMonth: number;
  sites: number;
  seats: number;
  retentionDays: number;
};

/* Consolidated per-tier limits. Free comes from FREE_LIMITS, Starter/Pro/
   Business from BILLABLE_PLANS[tier].limits, Enterprise is sentinel
   Infinity for now (admin-issued, no enforced quota). */
export const PLAN_LIMITS: Record<DbPlan, QuotaLimits> = {
  free: FREE_LIMITS,
  starter: BILLABLE_PLANS.starter.limits,
  pro: BILLABLE_PLANS.pro.limits,
  business: BILLABLE_PLANS.business.limits,
  enterprise: {
    testsPerMonth: Number.POSITIVE_INFINITY,
    sites: Number.POSITIVE_INFINITY,
    seats: Number.POSITIVE_INFINITY,
    retentionDays: 730,
  },
};
