import { BaseCommand } from '@adonisjs/core/ace'
import type { CommandOptions } from '@adonisjs/core/types/ace'
import { getStripe, STRIPE_LOOKUP_KEYS } from '#services/stripe'

/**
 * Crée / met à jour les Products + Prices Stripe pour Rubis.
 *
 * Idempotent : on cherche par `lookup_key` avant de créer. Si déjà
 * existant, on log "OK" et on passe. Pas d'écrasement (les prices Stripe
 * sont immuables — on ne peut pas modifier le montant d'un Price existant,
 * il faut en créer un nouveau).
 *
 * Lance ce command UNE FOIS au setup initial (test ou prod), puis quand
 * tu veux ajouter de nouveaux Prices.
 *
 *   node ace stripe:setup
 *
 * Pour rebattre les cartes : aller manuellement archive les Prices/Products
 * dans le dashboard Stripe puis relancer.
 */
export default class StripeSetup extends BaseCommand {
  static commandName = 'stripe:setup'
  static description = 'Crée les Products et Prices Stripe (Pro / Business, monthly + yearly)'

  static options: CommandOptions = {
    startApp: true,
  }

  async run() {
    // Lazy validation : provoque l'exception immédiate si la clé manque.
    getStripe()
    this.logger.info('Stripe setup — création des Products + Prices')

    // ---------------- PRO ----------------
    const proProduct = await this.ensureProduct({
      name: 'Rubis Pro',
      description:
        "Factures illimitées, OCR illimité, automatisation complète des relances. Pour les TPE actives qui ne veulent plus jamais y penser.",
      metadata: { plan_key: 'pro' },
    })

    await this.ensurePrice({
      productId: proProduct.id,
      lookupKey: STRIPE_LOOKUP_KEYS.pro_monthly,
      unitAmount: 1900, // 19,00 €
      interval: 'month',
      nickname: 'Pro mensuel',
    })

    await this.ensurePrice({
      productId: proProduct.id,
      lookupKey: STRIPE_LOOKUP_KEYS.pro_yearly,
      // 19 € × 12 = 228 €. -17% (= ~190 €) pour récompenser l'engagement annuel.
      unitAmount: 19_000,
      interval: 'year',
      nickname: 'Pro annuel (-17%)',
    })

    // ---------------- BUSINESS ----------------
    const bizProduct = await this.ensureProduct({
      name: 'Rubis Business',
      description:
        "Factures illimitées + 5 sièges utilisateurs + réponses depuis l'email de l'utilisateur. Pour les PME qui ont une vraie équipe.",
      metadata: { plan_key: 'business' },
    })

    await this.ensurePrice({
      productId: bizProduct.id,
      lookupKey: STRIPE_LOOKUP_KEYS.business_monthly,
      unitAmount: 4900, // 49,00 €
      interval: 'month',
      nickname: 'Business mensuel',
    })

    await this.ensurePrice({
      productId: bizProduct.id,
      lookupKey: STRIPE_LOOKUP_KEYS.business_yearly,
      // 49 € × 12 = 588 €. -17% (= ~490 €) annuel.
      unitAmount: 49_000,
      interval: 'year',
      nickname: 'Business annuel (-17%)',
    })

    this.logger.success('Stripe setup terminé.')
  }

  private async ensureProduct(input: {
    name: string
    description: string
    metadata: Record<string, string>
  }) {
    const stripe = getStripe()
    // Lookup via metadata (Stripe ne permet pas de lookup_key sur Product,
    // seulement sur Price). On utilise donc list + filter.
    const existing = await stripe.products.list({ active: true, limit: 100 })
    const found = existing.data.find(
      (p) => p.metadata?.['plan_key'] === input.metadata['plan_key']
    )
    if (found) {
      this.logger.info(`  Product ${input.name} : déjà existant (${found.id})`)
      return found
    }
    const created = await stripe.products.create({
      name: input.name,
      description: input.description,
      metadata: input.metadata,
    })
    this.logger.success(`  Product ${input.name} créé : ${created.id}`)
    return created
  }

  private async ensurePrice(input: {
    productId: string
    lookupKey: string
    unitAmount: number
    interval: 'month' | 'year'
    nickname: string
  }) {
    const stripe = getStripe()
    const existing = await stripe.prices.list({
      lookup_keys: [input.lookupKey],
      limit: 1,
    })
    if (existing.data[0]) {
      this.logger.info(
        `  Price ${input.nickname} : déjà existant (${existing.data[0].id})`
      )
      return existing.data[0]
    }
    const created = await stripe.prices.create({
      product: input.productId,
      unit_amount: input.unitAmount,
      currency: 'eur',
      recurring: { interval: input.interval },
      lookup_key: input.lookupKey,
      nickname: input.nickname,
    })
    this.logger.success(
      `  Price ${input.nickname} créé : ${created.id} (lookup=${input.lookupKey})`
    )
    return created
  }
}
