import UserModel from "../models/UserModel";
import { getStripe, stripeConfig } from "../config/stripe";

/** Stripe returned e.g. resource_missing for customer after key/account change or deleted test data. */
export function isStripeMissingCustomerError(err: unknown): boolean {
  if (typeof err !== "object" || err === null) return false;
  const e = err as { code?: string; param?: string; message?: string };
  if (e.code !== "resource_missing") return false;
  if (e.param === "customer") return true;
  return String(e.message ?? "")
    .toLowerCase()
    .includes("no such customer");
}

/**
 * Ensures the app user has a Stripe Customer (for saved cards / PaymentIntents).
 * If DB holds a customer id that no longer exists in Stripe, it is cleared and a new customer is created.
 */
export async function getOrCreateStripeCustomer(userId: string): Promise<string> {
  const user = await UserModel.findById(userId)
    .select("email fullName stripeCustomerId")
    .lean();
  if (!user) {
    throw new Error("User not found");
  }

  const stripe = getStripe();

  if (user.stripeCustomerId) {
    try {
      await stripe.customers.retrieve(user.stripeCustomerId);
      return user.stripeCustomerId;
    } catch (e) {
      if (isStripeMissingCustomerError(e)) {
        await UserModel.findByIdAndUpdate(userId, {
          $set: { stripeCustomerId: null },
        });
        console.warn(
          "[Stripe] Cleared stale stripeCustomerId for user",
          userId,
          "- customer missing in this Stripe account"
        );
      } else {
        throw e;
      }
    }
  }

  const customer = await stripe.customers.create({
    email: user.email || undefined,
    name: user.fullName || undefined,
    metadata: { appUserId: String(userId) },
  });

  await UserModel.findByIdAndUpdate(userId, {
    $set: { stripeCustomerId: customer.id },
  });

  return customer.id;
}

/**
 * Create Stripe Customer at signup / verify when Stripe is configured.
 * Never throws — logs and returns null so registration still succeeds if Stripe fails.
 */
export async function ensureStripeCustomerAtRegistration(
  userId: string
): Promise<string | null> {
  if (!stripeConfig.secretKey?.trim()) {
    return null;
  }
  try {
    return await getOrCreateStripeCustomer(userId);
  } catch (e) {
    console.error("[Stripe] ensureStripeCustomerAtRegistration:", userId, e);
    return null;
  }
}
