import type { Plan } from '@bmm/llm';
import Stripe from 'stripe';
import { config } from '../config.js';
import { getRedis } from './redis.js';

/**
 * Stripe client (null when no secret key is configured — e.g. in dev/test).
 * `apiVersion` pinned to the current default to avoid silent breakage when
 * Stripe rolls out new defaults.
 */
export const stripe: Stripe | null = config.STRIPE_SECRET_KEY
  ? new Stripe(config.STRIPE_SECRET_KEY, {
      // biome-ignore lint/suspicious/noExplicitAny: SDK type lags behind real API version strings
      apiVersion: '2025-10-29.acacia' as any,
      typescript: true,
    })
  : null;

export type PriceTier = 'pro_monthly' | 'pro_yearly' | 'team_monthly' | 'team_yearly';

export function priceIdForTier(tier: PriceTier): string | undefined {
  switch (tier) {
    case 'pro_monthly':
      return config.STRIPE_PRICE_PRO_MONTHLY;
    case 'pro_yearly':
      return config.STRIPE_PRICE_PRO_YEARLY;
    case 'team_monthly':
      return config.STRIPE_PRICE_TEAM_MONTHLY;
    case 'team_yearly':
      return config.STRIPE_PRICE_TEAM_YEARLY;
  }
}

/** Reverse map: which plan does a Stripe price id belong to. Unknown → hobby. */
export function planFromPriceId(priceId: string | undefined): Plan {
  if (!priceId) return 'hobby';
  if (
    priceId === config.STRIPE_PRICE_PRO_MONTHLY ||
    priceId === config.STRIPE_PRICE_PRO_YEARLY
  ) {
    return 'pro';
  }
  if (
    priceId === config.STRIPE_PRICE_TEAM_MONTHLY ||
    priceId === config.STRIPE_PRICE_TEAM_YEARLY
  ) {
    return 'team';
  }
  return 'hobby';
}

/**
 * Idempotency for Stripe webhooks. Stripe retries failed deliveries — we must
 * dedupe by event.id or we'd e.g. double-cancel a subscription. SET NX with a
 * 7-day TTL covers Stripe's full retry window.
 *
 * Returns true if this event was already processed (caller should skip).
 */
export async function isDuplicateEvent(eventId: string): Promise<boolean> {
  const redis = getRedis();
  const key = `stripe:event:${eventId}`;
  const set = await redis.set(key, '1', 'EX', 7 * 24 * 60 * 60, 'NX');
  return set === null;
}

/**
 * Sanity-check that price-id env vars actually contain price ids — a common
 * setup mistake is to paste the product id (prod_…) instead. Logs loudly on
 * boot so we discover misconfiguration before the first checkout attempt.
 */
export function validateStripePriceConfig(log: { warn: (msg: string) => void }): void {
  const checks: Array<[string, string | undefined]> = [
    ['STRIPE_PRICE_PRO_MONTHLY', config.STRIPE_PRICE_PRO_MONTHLY],
    ['STRIPE_PRICE_PRO_YEARLY', config.STRIPE_PRICE_PRO_YEARLY],
    ['STRIPE_PRICE_TEAM_MONTHLY', config.STRIPE_PRICE_TEAM_MONTHLY],
    ['STRIPE_PRICE_TEAM_YEARLY', config.STRIPE_PRICE_TEAM_YEARLY],
  ];
  for (const [name, value] of checks) {
    if (!value) continue;
    if (!value.startsWith('price_')) {
      log.warn(
        `[stripe] ${name} does not start with "price_" (got "${value.slice(0, 6)}…") — ` +
          'Stripe Checkout will reject this. Paste the PRICE id (price_…) from the product page, not the product id (prod_…).',
      );
    }
  }
}
