/**
 * Stripe client
 * Handles all interactions with Stripe API
 */

import Stripe from "stripe"
import { Money } from "./money"
import { env } from "./env"

const stripe = new Stripe(env.STRIPE_SECRET_KEY, {
  apiVersion: "2025-02-24.acacia",
  typescript: true,
})

export interface CreatePaymentIntentParams {
  orderId: number
  amountCents: number
  currency: string
  email: string
  description?: string
  /** Additional metadata to store on the PaymentIntent (e.g. pricing breakdown) */
  metadata?: Record<string, string>
}

export class StripeClient {
  /**
   * Create or retrieve existing PaymentIntent for order
   * Uses idempotency to ensure 1 PaymentIntent per WooCommerce order
   */
  static async createOrGetPaymentIntent(params: CreatePaymentIntentParams): Promise<Stripe.PaymentIntent> {
    const { orderId, amountCents, currency, email, description, metadata: extraMetadata } = params

    // Validate amount
    if (!Money.validate(amountCents)) {
      throw new Error("Invalid amount: must be positive integer in cents")
    }

    const idempotencyKey = `wc_order_${orderId}`

    try {
      const paymentIntentParams: Stripe.PaymentIntentCreateParams = {
        amount: amountCents,
        currency: currency.toLowerCase(),
        automatic_payment_methods: {
          enabled: true,
        },
        description: description || `Order #${orderId}`,
        metadata: {
          wc_order_id: orderId.toString(),
          ...extraMetadata,
        },
      }

      // Only add receipt_email if email is valid
      if (email && email.trim().length > 0 && email.includes('@')) {
        paymentIntentParams.receipt_email = email.trim()
      }

      const paymentIntent = await stripe.paymentIntents.create(
        paymentIntentParams,
        {
          idempotencyKey,
        },
      )

      return paymentIntent
    } catch (error) {
      if (error instanceof Stripe.errors.StripeError) {
        throw new Error(`Stripe error: ${error.message}`)
      }
      throw error
    }
  }

  /**
   * Verify Stripe webhook signature
   */
  static constructEvent(payload: string | Buffer, signature: string): Stripe.Event {
    try {
      return stripe.webhooks.constructEvent(payload, signature, env.STRIPE_WEBHOOK_SECRET)
    } catch (error) {
      throw new Error("Invalid webhook signature")
    }
  }

  /**
   * Retrieve PaymentIntent by ID
   */
  static async getPaymentIntent(paymentIntentId: string): Promise<Stripe.PaymentIntent> {
    return stripe.paymentIntents.retrieve(paymentIntentId)
  }

  /**
   * Get Stripe instance for advanced operations
   */
  static getClient(): Stripe {
    return stripe
  }
}
