import Stripe from 'stripe'; // Import the Stripe package
const stripe = Stripe(process.env.STRIPE_SECRET_KEY); // Initialize Stripe with your secret key

/**
 * @swagger
 * tags:
 *   name: Stripe
 *   description: "Stripe payment and subscription management"
 */

/**
 * @swagger
 * components:
 *   schemas:
 *     PaymentRequest:
 *       type: object
 *       required:
 *         - user
 *         - priceId
 *         - returnURL
 *         - merchantDisplayName
 *         - merchantCountryCode
 *       properties:
 *         user:
 *           type: object
 *           description: User details containing name and email.
 *           properties:
 *             email:
 *               type: string
 *               example: "customer@example.com"
 *             lastname:
 *               type: string
 *               example: "Doe"
 *         priceId:
 *           type: string
 *           description: The price ID for the subscription plan.
 *           example: "price_1PxA3QLHML5MMaxfCfob8i4s"
 *         returnURL:
 *           type: string
 *           description: The return URL after payment success.
 *           example: "goodpark://success"
 *         merchantDisplayName:
 *           type: string
 *           description: The display name of the merchant.
 *           example: "GoodPark"
 *         merchantCountryCode:
 *           type: string
 *           description: The country code of the merchant.
 *           example: "FR"
 *         applePayMerchantIdentifier:
 *           type: string
 *           description: Apple Pay merchant identifier.
 *           example: "merchant.fr.leadev.goodpark"
 *     SubscriptionDetails:
 *       type: object
 *       properties:
 *         id:
 *           type: string
 *           description: The ID of the subscription.
 *           example: "sub_12345ABCDE"
 *         status:
 *           type: string
 *           description: The status of the subscription.
 *           example: "active"
 *         current_period_start:
 *           type: integer
 *           description: The start of the current period in epoch timestamp.
 *           example: 1632960000
 *         current_period_end:
 *           type: integer
 *           description: The end of the current period in epoch timestamp.
 *           example: 1635648000
 *         plan:
 *           type: object
 *           properties:
 *             id:
 *               type: string
 *               description: The price ID of the plan.
 *               example: "price_1JWdqWFdsvRzR"
 *             nickname:
 *               type: string
 *               description: The nickname or name of the plan.
 *               example: "Monthly Plan"
 */


/**
 * @swagger
 * /stripe/createPayment:
 *   post:
 *     summary: Créer un abonnement Stripe avec PaymentSheet
 *     description: Crée un client Stripe, génère un abonnement avec un priceId donné et retourne les données nécessaires à l'initialisation du PaymentSheet.
 *     tags: [Stripe]
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             $ref: '#/components/schemas/PaymentRequest'
 *     responses:
 *       200:
 *         description: Données nécessaires à l'initialisation du PaymentSheet retournées avec succès.
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 clientSecret:
 *                   type: string
 *                   example: pi_3Nx7X..._secret_...
 *                 customerId:
 *                   type: string
 *                   example: cus_Lm6Dg3s...
 *                 ephemeralKeySecret:
 *                   type: string
 *                   example: ek_test_1Mn...
 *                 returnURL:
 *                   type: string
 *                   example: "goodpark://success"
 *                 merchantDisplayName:
 *                   type: string
 *                   example: "GoodPark"
 *                 merchantCountryCode:
 *                   type: string
 *                   example: "FR"
 *                 applePayMerchantIdentifier:
 *                   type: string
 *                   example: "merchant.fr.leadev.goodpark"
 *       500:
 *         description: Erreur serveur lors de la création du paiement
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 error:
 *                   type: string
 *                   example: "Erreur création PaymentIntent"
 */
export const createPayment = async (req, res) => {
  const {
    user,
    priceId,
    returnURL,
    merchantDisplayName,
    merchantCountryCode,
    applePayMerchantIdentifier,
  } = req.body;

  try {
    // Step 1: Create Customer
    const { customerId, ephemeralKeySecret } = await createCustomer(user);

    // Step 2: Create Subscription
    const { clientSecret } = await createSubscription({ priceId, customerId });

    // Send back clientSecret, customerId, ephemeralKeySecret to initialize PaymentSheet on the client
    res.json({
      clientSecret,
      customerId,
      ephemeralKeySecret,
      returnURL,
      merchantDisplayName,
      merchantCountryCode,
      applePayMerchantIdentifier,
    });
  } catch (error) {
    console.error('Error creating payment:', error);
    res.status(500).json({ error: error.message });
  }
};

// STEP 1: Create a Customer
const createCustomer = async (user) => {
  try {
    // Step 1: Check if the customer already exists by searching with the email
    const existingCustomers = await stripe.customers.list({
      email: user.email,
      limit: 1, // Only need the first customer if it exists
    });

    let customer, ephemeralKey;

    if (existingCustomers.data.length > 0) {
      // If a customer with the email already exists, use the existing one
      customer = existingCustomers.data[0];
      console.log(`Customer already exists: ${customer.id}`);
    } else {
      // Step 2: Create a new customer if none was found
      customer = await stripe.customers.create({
        email: user.email,
        name: user.lastname,
      });
      console.log(`New customer created: ${customer.id}`);
    }

    // Step 3: Create an ephemeral key for the customer (new or existing)
    ephemeralKey = await stripe.ephemeralKeys.create(
      { customer: customer.id },
      { apiVersion: '2024-06-20' } // Latest API version
    );

    return {
      customerId: customer.id,
      ephemeralKeySecret: ephemeralKey.secret,
    };
  } catch (error) {
    throw new Error(`Error creating or fetching customer: ${error.message}`);
  }
};


// STEP 2: Create a Subscription
const createSubscription = async ({ priceId, customerId }) => {
  try {
    // 1. Vérifier si le client a déjà un abonnement actif ou en période d’essai pour ce priceId
    const existingSubscriptions = await stripe.subscriptions.list({
      customer: customerId,
      status: 'all',
    });

    const alreadySubscribed = existingSubscriptions.data.some(sub => {
      return (
        ['active', 'trialing'].includes(sub.status) &&
        sub.items.data.some(item => item.price.id === priceId)
      );
    });

    if (alreadySubscribed) {
      throw new Error("Ce client a déjà un abonnement actif ou en essai pour ce produit.");
    }

    // 2. Créer l'abonnement si aucun actif pour ce produit
    const subscription = await stripe.subscriptions.create({
      customer: customerId,
      items: [{ price: priceId }],
      payment_behavior: 'default_incomplete',
      expand: ['latest_invoice.payment_intent'],
    });

    const clientSecret = subscription.latest_invoice.payment_intent.client_secret;

    return { clientSecret };
  } catch (error) {
    throw new Error(`Erreur lors de la création de l'abonnement : ${error.message}`);
  }
};

/**
 * @swagger
 * /stripe/createAdPaymentIntent:
 *   post:
 *     summary: Créer un paiement unique pour une publicité
 *     description: Crée un PaymentIntent pour un achat ponctuel via Stripe.
 *     tags: [Stripe]
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required:
 *               - user
 *               - amount
 *             properties:
 *               user:
 *                 type: object
 *                 required:
 *                   - email
 *                 properties:
 *                   email:
 *                     type: string
 *                     example: "contact@client.fr"
 *               amount:
 *                 type: integer
 *                 description: Montant total en centimes
 *                 example: 4000
 *     responses:
 *       200:
 *         description: PaymentIntent créé avec succès
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 clientSecret:
 *                   type: string
 *                   description: Clé secrète pour confirmer le paiement côté client
 *                   example: "pi_3Nj8Zt4aQG..._secret_wjJ78ds6Y..."
 *       500:
 *         description: Erreur serveur
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 error:
 *                   type: string
 *                   example: "Erreur lors de la création du PaymentIntent"
 */
export const createAdPaymentIntent = async (req, res) => {
  const { user, amount } = req.body;

  try {
    // Créer un PaymentIntent classique
    const paymentIntent = await stripe.paymentIntents.create({
      amount: amount, // en centimes
      currency: 'eur',
      receipt_email: user.email,
      metadata: {
        usage: 'ad',
        userEmail: user.email,
      },
      automatic_payment_methods: { enabled: true },
    });

    res.json({ clientSecret: paymentIntent.client_secret });
  } catch (error) {
    console.error("Erreur création PaymentIntent:", error.message);
    res.status(500).json({ error: error.message });
  }
};



/**
 * @swagger
 * /stripe/subscription/details:
 *   post:
 *     summary: Get Stripe Customer Subscription Details
 *     description: Fetch the subscription details of a Stripe customer based on the customer ID.
 *     tags: [Stripe]
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             properties:
 *               customerId:
 *                 type: string
 *                 example: cus_12345ABCDE
 *                 description: The Stripe customer ID for which subscription details will be retrieved.
 *     responses:
 *       200:
 *         description: Subscription details retrieved successfully
 *         content:
 *           application/json:
 *             schema:
 *               $ref: '#/components/schemas/SubscriptionDetails'
 *       500:
 *         description: Internal server error. Failed to fetch subscription details.
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 error:
 *                   type: string
 *                   description: Error message explaining the issue.
 */
export const subscriptionDetails = async (req, res) => {
  const { customerId } = req.body;

  try {
    // Fetch the customer's active subscriptions
    const subscriptions = await stripe.subscriptions.list({
      customer: customerId,
      status: 'all',
    });

    // Return subscription details to the frontend
    res.json(subscriptions);
  } catch (error) {
    console.error('Error fetching subscription details:', error);
    res.status(500).json({ error: error.message });
  }
};




/**
 * @swagger
 * /stripe/webhook:
 *   post:
 *     summary: Webhook to listen for Stripe events
 *     description: This endpoint listens for Stripe webhook events and handles subscription activation, payment success, and other events.
 *     tags: [Stripe]
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *     responses:
 *       200:
 *         description: Webhook event processed successfully
 *       400:
 *         description: Webhook signature verification failed
 *       500:
 *         description: Internal server error
 */
export const webhookToListenForStripeEvents = async (req, res) => {
  const sig = req.headers['stripe-signature'];
  let event;

  try {
    event = stripe.webhooks.constructEvent(
      req.body,
      sig,
      process.env.STRIPE_WEBHOOK_SECRET // Your Stripe Webhook Secret
    );
  } catch (err) {
    console.error('Webhook signature verification failed.', err.message);
    return res.status(400).send(`Webhook Error: ${err.message}`);
  }

  // Handle the events
  switch (event.type) {
    case 'checkout.session.completed':
      const session = event.data.object;
      console.log(`Payment successful for session ${session.id}`);
      // Fulfill the subscription (e.g., activate in your database)
      handleCheckoutSessionCompleted(session);
      break;

    case 'invoice.payment_succeeded':
      const invoice = event.data.object;
      console.log(`Payment successful for invoice ${invoice.id}`);
      const customerEmail = invoice.customer_email || invoice.customer_details.email;
      const amountPaid = invoice.amount_paid / 100; // Convert from cents
      const invoiceUrl = invoice.hosted_invoice_url;
      // Send an invoice to the customer
      sendInvoiceToCustomer(customerEmail, amountPaid, invoiceUrl);
      break;

    case 'invoice.payment_failed':
      const failedInvoice = event.data.object;
      console.log(`Payment failed for invoice ${failedInvoice.id}`);
      // Handle failed payment
      handlePaymentFailure(failedInvoice);
      break;

    default:
      console.log(`Unhandled event type: ${event.type}`);
  }

  res.json({ received: true });
};

/**
 * @swagger
 * /stripe/subscription/details/byemail/{email}:
 *   get:
 *     summary: Get subscriptions by customer email
 *     description: Fetches the list of Stripe subscriptions for a customer using their email address.
 *     tags: [Stripe]
 *     parameters:
 *       - in: path
 *         name: email
 *         required: true
 *         schema:
 *           type: string
 *         description: The email address of the customer to retrieve subscriptions for.
 *     responses:
 *       200:
 *         description: Successfully retrieved list of subscriptions for the customer.
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 object:
 *                   type: string
 *                   example: list
 *                 data:
 *                   type: array
 *                   items:
 *                     type: object
 *                     properties:
 *                       id:
 *                         type: string
 *                         description: Subscription ID
 *                         example: sub_1Q6XbDLHML5MMaxfvaFKYqdq
 *                       status:
 *                         type: string
 *                         description: The status of the subscription.
 *                         example: active
 *                       customer:
 *                         type: string
 *                         description: The ID of the customer who owns the subscription.
 *                         example: cus_QuM8X8qpu65Wve
 *                       current_period_start:
 *                         type: integer
 *                         description: Timestamp when the current period started.
 *                         example: 1728133243
 *                       current_period_end:
 *                         type: integer
 *                         description: Timestamp when the current period ends.
 *                         example: 1736082043
 *                       plan:
 *                         type: object
 *                         properties:
 *                           id:
 *                             type: string
 *                             description: The plan ID.
 *                             example: price_1PxA3QLHML5MMaxfCfob8i4s
 *                           amount:
 *                             type: integer
 *                             description: Amount charged per interval (in cents).
 *                             example: 3000
 *                           currency:
 *                             type: string
 *                             description: Currency of the subscription.
 *                             example: eur
 *                           interval:
 *                             type: string
 *                             description: Interval type (day, month, year).
 *                             example: month
 *                           interval_count:
 *                             type: integer
 *                             description: The number of intervals between subscription billings.
 *                             example: 3
 *                       created:
 *                         type: integer
 *                         description: Timestamp when the subscription was created.
 *                         example: 1728133243
 *                       canceled_at:
 *                         type: integer
 *                         description: Timestamp when the subscription was canceled.
 *                         example: null
 *                       cancel_at_period_end:
 *                         type: boolean
 *                         description: If true, the subscription will be canceled at the end of the current period.
 *                         example: false
 *       404:
 *         description: No customer found with the provided email.
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 error:
 *                   type: string
 *                   example: No customer found with this email.
 *       500:
 *         description: Internal server error.
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 error:
 *                   type: string
 *                   example: Internal server error.
 */
export const fetchSusbcriptionListByCustomerEmail = async (req, res) => {
  try {
    const { email } = req.params;

    // Step 1: Find the customer by email
    const customers = await stripe.customers.list({
      email,
      limit: 1, // Assuming one customer per email
    });

    if (customers.data.length === 0) {
      return res.status(404).json({ error: 'No customer found with this email' });
    }

    const customer = customers.data[0];

    // Step 2: Fetch subscriptions for this customer
    const subscriptions = await stripe.subscriptions.list({
      customer: customer.id,
    });

    return res.status(200).json(subscriptions);
  } catch (error) {
    console.error('Error fetching subscription:', error);
    return res.status(500).json({ error: error.message });
  }
};

/**
 * @swagger
 * /stripe/subscription/cancel/{subscriptionId}:
 *   post:
 *     summary: Set subscription to cancel at the end of the current period
 *     description: Cancels a Stripe subscription at the end of the current billing period using the subscription ID.
 *     tags: [Stripe]
 *     parameters:
 *       - in: path
 *         name: subscriptionId
 *         required: true
 *         schema:
 *           type: string
 *         description: The ID of the subscription to cancel.
 *     responses:
 *       200:
 *         description: Successfully set the subscription to cancel at the end of the current period.
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 id:
 *                   type: string
 *                   description: Subscription ID
 *                   example: sub_1Q6XbDLHML5MMaxfvaFKYqdq
 *                 status:
 *                   type: string
 *                   description: The status of the subscription.
 *                   example: active
 *                 cancel_at_period_end:
 *                   type: boolean
 *                   description: If true, the subscription will be canceled at the end of the current period.
 *                   example: true
 *                 current_period_end:
 *                   type: integer
 *                   description: Timestamp when the current period ends.
 *                   example: 1736082043
 *       404:
 *         description: No subscription found with the provided subscription ID.
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 error:
 *                   type: string
 *                   example: No subscription found with this ID.
 *       500:
 *         description: Internal server error.
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 error:
 *                   type: string
 *                   example: Internal server error.
 */
export const cancelStripeSubscriptionAtPeriodEnd = async (req, res) => {
  try {
    const { subscriptionId } = req.params;

    // Step 1: Retrieve the subscription by ID
    const subscription = await stripe.subscriptions.retrieve(subscriptionId);

    if (!subscription) {
      return res.status(404).json({ error: 'No subscription found with this ID' });
    }

    // Step 2: Set cancel_at_period_end to true, allowing the user to continue using the subscription until the end of the current period
    const updatedSubscription = await stripe.subscriptions.update(subscriptionId, {
      cancel_at_period_end: true,
    });

    // Step 3: Return the updated subscription details
    return res.status(200).json(updatedSubscription);
  } catch (error) {
    console.error('Error setting subscription to cancel at period end:', error);
    return res.status(500).json({ error: error.message });
  }
};




// Function to handle checkout session completed
const handleCheckoutSessionCompleted = (session) => {
  // Logic to activate the user's subscription in the database
  console.log(`Activating subscription for session ${session.id}`);
  console.log(session);
};

// Function to send the invoice to the customer
const sendInvoiceToCustomer = (email, amountPaid, invoiceUrl) => {
  console.log(`Sending invoice to ${email} for amount ${amountPaid}`);
  // Here, you can send an email using a service like Nodemailer, SendGrid, etc.
  console.log(`Invoice available at: ${invoiceUrl}`);
};

// Function to handle payment failure
const handlePaymentFailure = (invoice) => {
  const customerEmail = invoice.customer_email || invoice.customer_details.email;
  console.log(`Payment failed for customer ${customerEmail}.`);
  // You can notify the user about payment failure or retry the payment.
};

