/**
 * Script d'initialisation Stripe.
 *
 * Crée (ou récupère s'ils existent déjà) les produits et prix de Freedge,
 * puis affiche les IDs à copier dans `.env`. Idempotent — peut être relancé
 * sans danger grâce aux `lookup_key` sur les prix.
 *
 * Usage :
 *   pnpm stripe:setup              # juste afficher les IDs
 *   pnpm stripe:setup --write-env  # écrire directement dans backend/.env
 *
 * Nécessite `STRIPE_SECRET_KEY` dans l'environnement (chargé depuis .env).
 */

import 'dotenv/config';
import Stripe from 'stripe';
import * as fs from 'node:fs';
import * as path from 'node:path';

// ---------------------------------------------------------------------------
// Configuration des plans à créer
// ---------------------------------------------------------------------------

interface PlanDefinition {
  envKey: 'STRIPE_PRICE_ID_ESSENTIAL' | 'STRIPE_PRICE_ID_PREMIUM';
  lookupKey: string;
  product: {
    name: string;
    description: string;
  };
  price: {
    unitAmount: number; // centimes
    currency: string;
    interval: 'month' | 'year';
  };
}

const PLANS: PlanDefinition[] = [
  {
    envKey: 'STRIPE_PRICE_ID_ESSENTIAL',
    lookupKey: 'freedge_essential_monthly',
    product: {
      name: 'Freedge Essentiel',
      description:
        '15 recettes par mois, reconnaissance vocale, préférences culinaires, sauvegarde illimitée.',
    },
    price: {
      unitAmount: 300, // 3,00 €
      currency: 'eur',
      interval: 'month',
    },
  },
  {
    envKey: 'STRIPE_PRICE_ID_PREMIUM',
    lookupKey: 'freedge_premium_monthly',
    product: {
      name: 'Freedge Premium',
      description:
        'Recettes illimitées, images haute qualité, reconnaissance vocale, support prioritaire.',
    },
    price: {
      unitAmount: 500, // 5,00 €
      currency: 'eur',
      interval: 'month',
    },
  },
];

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

const YELLOW = '\x1b[33m';
const GREEN = '\x1b[32m';
const RED = '\x1b[31m';
const CYAN = '\x1b[36m';
const DIM = '\x1b[2m';
const BOLD = '\x1b[1m';
const RESET = '\x1b[0m';

function log(msg: string) {
  // eslint-disable-next-line no-console
  console.log(msg);
}

function fail(msg: string): never {
  log(`${RED}✗ ${msg}${RESET}`);
  process.exit(1);
}

/**
 * Trouve un prix existant par `lookup_key`, ou crée le produit + prix
 * sinon. Retourne toujours un objet Stripe.Price.
 */
async function ensurePlan(
  stripe: Stripe,
  plan: PlanDefinition
): Promise<Stripe.Price> {
  // Cherche par lookup_key (idempotent)
  const existing = await stripe.prices.list({
    lookup_keys: [plan.lookupKey],
    expand: ['data.product'],
    limit: 1,
  });

  if (existing.data.length > 0) {
    const price = existing.data[0];
    const product = price.product as Stripe.Product;
    log(
      `  ${DIM}→${RESET} ${plan.product.name} ${DIM}(déjà existant)${RESET}`
    );
    log(`    ${DIM}product: ${product.id}${RESET}`);
    log(`    ${DIM}price:   ${price.id}${RESET}`);
    return price;
  }

  // Sinon, crée le produit
  log(`  ${CYAN}+${RESET} Création de ${plan.product.name}…`);
  const product = await stripe.products.create({
    name: plan.product.name,
    description: plan.product.description,
    metadata: {
      app: 'freedge',
      plan_key: plan.lookupKey,
    },
  });

  // Puis le prix récurrent avec lookup_key pour la prochaine fois
  const price = await stripe.prices.create({
    product: product.id,
    unit_amount: plan.price.unitAmount,
    currency: plan.price.currency,
    recurring: { interval: plan.price.interval },
    lookup_key: plan.lookupKey,
    nickname: `${plan.product.name} — mensuel`,
    metadata: {
      app: 'freedge',
      plan_key: plan.lookupKey,
    },
  });

  log(`    ${GREEN}✓${RESET} product: ${product.id}`);
  log(`    ${GREEN}✓${RESET} price:   ${price.id}`);
  return price;
}

/**
 * Met à jour (ou ajoute) une variable dans le fichier .env.
 * Préserve l'ordre et les commentaires des autres lignes.
 */
function upsertEnvVar(envPath: string, key: string, value: string): void {
  let content = '';
  if (fs.existsSync(envPath)) {
    content = fs.readFileSync(envPath, 'utf-8');
  }

  const lineRegex = new RegExp(`^${key}=.*$`, 'm');
  if (lineRegex.test(content)) {
    content = content.replace(lineRegex, `${key}=${value}`);
  } else {
    content = (content.trimEnd() + `\n${key}=${value}\n`).trimStart();
  }

  fs.writeFileSync(envPath, content);
}

// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------

async function main() {
  const writeEnv = process.argv.includes('--write-env');

  const secretKey = process.env.STRIPE_SECRET_KEY;
  if (!secretKey) {
    fail(
      'STRIPE_SECRET_KEY manquante. Définis-la dans backend/.env puis relance.'
    );
  }
  if (!secretKey.startsWith('sk_')) {
    fail(`STRIPE_SECRET_KEY ne ressemble pas à une clé Stripe : ${secretKey.slice(0, 8)}…`);
  }

  const isLive = secretKey.startsWith('sk_live_');
  log('');
  log(`${BOLD}🔧 Freedge — Initialisation Stripe${RESET}`);
  log(
    `${DIM}Mode : ${isLive ? `${RED}LIVE ⚠️${RESET}${DIM}` : `${GREEN}TEST${RESET}${DIM}`}${RESET}`
  );
  log('');

  if (isLive) {
    log(
      `${YELLOW}⚠️  Tu utilises une clé LIVE. Les produits seront créés en production.${RESET}`
    );
    log(`${YELLOW}   Appuie sur Ctrl+C dans les 5 secondes pour annuler.${RESET}`);
    log('');
    await new Promise((r) => setTimeout(r, 5000));
  }

  const stripe = new Stripe(secretKey, {
    apiVersion:
      (process.env.STRIPE_API_VERSION as Stripe.StripeConfig['apiVersion']) ?? '2023-10-16',
    typescript: true,
  });

  log(`${BOLD}Plans à provisionner :${RESET}`);
  const results: Array<{ envKey: string; priceId: string }> = [];
  for (const plan of PLANS) {
    try {
      const price = await ensurePlan(stripe, plan);
      results.push({ envKey: plan.envKey, priceId: price.id });
    } catch (err) {
      log(`  ${RED}✗${RESET} ${plan.product.name} : ${(err as Error).message}`);
      process.exit(1);
    }
  }

  log('');
  log(`${BOLD}Résultat :${RESET}`);
  log('');
  for (const { envKey, priceId } of results) {
    log(`  ${CYAN}${envKey}${RESET}=${priceId}`);
  }
  log('');

  if (writeEnv) {
    const envPath = path.resolve(process.cwd(), '.env');
    for (const { envKey, priceId } of results) {
      upsertEnvVar(envPath, envKey, priceId);
    }
    log(`${GREEN}✓${RESET} ${envPath} mis à jour.`);
  } else {
    log(
      `${DIM}Ajoute ces lignes à backend/.env (ou relance avec --write-env pour le faire automatiquement).${RESET}`
    );
  }

  log('');

  // Rappels utiles
  log(`${BOLD}Prochaines étapes :${RESET}`);
  log(`  1. ${DIM}Activer le Customer Portal${RESET}`);
  log(
    `     ${DIM}https://dashboard.stripe.com/${isLive ? '' : 'test/'}settings/billing/portal${RESET}`
  );
  log(`  2. ${DIM}Lancer le listener webhook en local${RESET}`);
  log(`     ${DIM}stripe listen --forward-to localhost:3000/stripe/webhook${RESET}`);
  log(`  3. ${DIM}Copier le whsec_ affiché dans STRIPE_WEBHOOK_SECRET${RESET}`);
  log('');
}

main().catch((err) => {
  log('');
  fail(err instanceof Error ? err.message : String(err));
});
