const express = require("express");
const { Op } = require("sequelize");
const { Rental, Item, User } = require("../models"); // Import from models/index.js to get models with associations
const {
  authenticateToken,
  requireVerifiedEmail,
} = require("../middleware/auth");
const FeeCalculator = require("../utils/feeCalculator");
const RentalDurationCalculator = require("../utils/rentalDurationCalculator");
const RefundService = require("../services/refundService");
const LateReturnService = require("../services/lateReturnService");
const PayoutService = require("../services/payoutService");
const DamageAssessmentService = require("../services/damageAssessmentService");
const StripeWebhookService = require("../services/stripeWebhookService");
const StripeService = require("../services/stripeService");
const emailServices = require("../services/email");
const EventBridgeSchedulerService = require("../services/eventBridgeSchedulerService");
const logger = require("../utils/logger");
const { PaymentError } = require("../utils/stripeErrors");
const { validateS3Keys } = require("../utils/s3KeyValidator");
const { IMAGE_LIMITS } = require("../config/imageLimits");
const { isActive, getEffectiveStatus } = require("../utils/rentalStatus");
const router = express.Router();

// Helper to add displayStatus to rental response
const addDisplayStatus = (rental) => {
  if (!rental) return rental;
  const rentalJson = rental.toJSON ? rental.toJSON() : rental;
  return {
    ...rentalJson,
    displayStatus: getEffectiveStatus(rentalJson),
  };
};

// Helper to add displayStatus to array of rentals
const addDisplayStatusToArray = (rentals) => {
  return rentals.map(addDisplayStatus);
};

// Helper function to check and update review visibility
const checkAndUpdateReviewVisibility = async (rental) => {
  const now = new Date();
  const seventyTwoHoursInMs = 72 * 60 * 60 * 1000; // 72 hours

  let needsUpdate = false;
  let updates = {};

  // Check if both reviews are submitted
  if (rental.itemReviewSubmittedAt && rental.renterReviewSubmittedAt) {
    if (!rental.itemReviewVisible || !rental.renterReviewVisible) {
      updates.itemReviewVisible = true;
      updates.renterReviewVisible = true;
      needsUpdate = true;
    }
  } else {
    // Check item review visibility (72-hour rule)
    if (rental.itemReviewSubmittedAt && !rental.itemReviewVisible) {
      const timeSinceSubmission = now - new Date(rental.itemReviewSubmittedAt);
      if (timeSinceSubmission >= seventyTwoHoursInMs) {
        updates.itemReviewVisible = true;
        needsUpdate = true;
      }
    }

    // Check renter review visibility (72-hour rule)
    if (rental.renterReviewSubmittedAt && !rental.renterReviewVisible) {
      const timeSinceSubmission =
        now - new Date(rental.renterReviewSubmittedAt);
      if (timeSinceSubmission >= seventyTwoHoursInMs) {
        updates.renterReviewVisible = true;
        needsUpdate = true;
      }
    }
  }

  if (needsUpdate) {
    await rental.update(updates);
  }

  return rental;
};

router.get("/renting", authenticateToken, async (req, res) => {
  try {
    const rentals = await Rental.findAll({
      where: { renterId: req.user.id },
      // Remove explicit attributes to let Sequelize handle missing columns gracefully
      include: [
        { model: Item, as: "item" },
        {
          model: User,
          as: "owner",
          attributes: ["id", "firstName", "lastName", "imageFilename"],
        },
      ],
      order: [["createdAt", "DESC"]],
    });

    res.json(addDisplayStatusToArray(rentals));
  } catch (error) {
    const reqLogger = logger.withRequestId(req.id);
    reqLogger.error("Error in renting route", {
      error: error.message,
      stack: error.stack,
      userId: req.user.id,
    });
    res.status(500).json({ error: "Failed to fetch rentals" });
  }
});

router.get("/owning", authenticateToken, async (req, res) => {
  try {
    // Reconcile payout statuses with Stripe before returning data
    // This handles cases where webhooks were missed
    try {
      await StripeWebhookService.reconcilePayoutStatuses(req.user.id);
    } catch (reconcileError) {
      // Log but don't fail the request - still return rentals
      const reqLogger = logger.withRequestId(req.id);
      reqLogger.error("Error reconciling payout statuses", {
        error: reconcileError.message,
        userId: req.user.id,
      });
    }

    const rentals = await Rental.findAll({
      where: { ownerId: req.user.id },
      // Remove explicit attributes to let Sequelize handle missing columns gracefully
      include: [
        { model: Item, as: "item" },
        {
          model: User,
          as: "renter",
          attributes: ["id", "firstName", "lastName", "imageFilename"],
        },
      ],
      order: [["createdAt", "DESC"]],
    });

    res.json(addDisplayStatusToArray(rentals));
  } catch (error) {
    const reqLogger = logger.withRequestId(req.id);
    reqLogger.error("Error in owning route", {
      error: error.message,
      stack: error.stack,
      userId: req.user.id,
    });
    res.status(500).json({ error: "Failed to fetch listings" });
  }
});

// Get count of pending rental requests for owner
router.get("/pending-requests-count", authenticateToken, async (req, res) => {
  try {
    const count = await Rental.count({
      where: {
        ownerId: req.user.id,
        status: "pending",
      },
    });

    res.json({ count });
  } catch (error) {
    const reqLogger = logger.withRequestId(req.id);
    reqLogger.error("Error getting pending rental count", {
      error: error.message,
      stack: error.stack,
      userId: req.user.id,
    });
    res.status(500).json({ error: "Failed to get pending rental count" });
  }
});

// Get rental by ID
router.get("/:id", authenticateToken, async (req, res) => {
  try {
    const rental = await Rental.findByPk(req.params.id, {
      include: [
        { model: Item, as: "item" },
        {
          model: User,
          as: "owner",
          attributes: ["id", "firstName", "lastName"],
        },
        {
          model: User,
          as: "renter",
          attributes: ["id", "firstName", "lastName"],
        },
      ],
    });

    if (!rental) {
      return res.status(404).json({ error: "Rental not found" });
    }

    // Check if user is authorized to view this rental
    if (rental.ownerId !== req.user.id && rental.renterId !== req.user.id) {
      return res
        .status(403)
        .json({ error: "Unauthorized to view this rental" });
    }

    res.json(addDisplayStatus(rental));
  } catch (error) {
    const reqLogger = logger.withRequestId(req.id);
    reqLogger.error("Error fetching rental", {
      error: error.message,
      stack: error.stack,
      rentalId: req.params.id,
      userId: req.user.id,
    });
    res.status(500).json({ error: "Failed to fetch rental" });
  }
});

router.post("/", authenticateToken, requireVerifiedEmail, async (req, res) => {
  try {
    const {
      itemId,
      startDateTime,
      endDateTime,
      deliveryMethod,
      deliveryAddress,
      intendedUse,
      stripePaymentMethodId,
    } = req.body;

    const item = await Item.findByPk(itemId);
    if (!item) {
      return res.status(404).json({ error: "Item not found" });
    }

    if (!item.isAvailable) {
      return res.status(400).json({ error: "Item is not available" });
    }

    let rentalStartDateTime, rentalEndDateTime, totalAmount;

    // New UTC datetime format
    rentalStartDateTime = new Date(startDateTime);
    rentalEndDateTime = new Date(endDateTime);

    // Validate date formats
    if (isNaN(rentalStartDateTime.getTime())) {
      return res.status(400).json({ error: "Invalid start date format" });
    }
    if (isNaN(rentalEndDateTime.getTime())) {
      return res.status(400).json({ error: "Invalid end date format" });
    }

    // Validate start date is not in the past (with 5 minute grace period for form submission)
    const now = new Date();
    const fiveMinutesAgo = new Date(now.getTime() - 5 * 60 * 1000);
    if (rentalStartDateTime < fiveMinutesAgo) {
      return res
        .status(400)
        .json({ error: "Start date cannot be in the past" });
    }

    // Validate end date/time is after start date/time
    if (rentalEndDateTime <= rentalStartDateTime) {
      return res
        .status(400)
        .json({ error: "End date/time must be after start date/time" });
    }

    // Calculate rental cost using duration calculator
    totalAmount = RentalDurationCalculator.calculateRentalCost(
      rentalStartDateTime,
      rentalEndDateTime,
      item
    );

    // Check for overlapping rentals using datetime ranges
    // Note: "active" rentals are stored as "confirmed" with startDateTime in the past
    // Two ranges [A,B] and [C,D] overlap if and only if A < D AND C < B
    // Here: existing rental [existingStart, existingEnd], new rental [rentalStartDateTime, rentalEndDateTime]
    // Overlap: existingStart < rentalEndDateTime AND rentalStartDateTime < existingEnd
    const overlappingRental = await Rental.findOne({
      where: {
        itemId,
        status: "confirmed",
        startDateTime: { [Op.not]: null },
        endDateTime: { [Op.not]: null },
        [Op.and]: [
          // existingStart < newEnd (existing rental starts before new one ends)
          { startDateTime: { [Op.lt]: rentalEndDateTime } },
          // existingEnd > newStart (existing rental ends after new one starts)
          { endDateTime: { [Op.gt]: rentalStartDateTime } },
        ],
      },
    });

    if (overlappingRental) {
      return res
        .status(400)
        .json({ error: "Item is already booked for these dates" });
    }

    // Calculate fees using FeeCalculator
    const fees = FeeCalculator.calculateRentalFees(totalAmount);

    // Validate that payment method was provided for paid rentals
    if (totalAmount > 0 && !stripePaymentMethodId) {
      return res
        .status(400)
        .json({ error: "Payment method is required for paid rentals" });
    }

    const rentalData = {
      itemId,
      renterId: req.user.id,
      ownerId: item.ownerId,
      startDateTime: rentalStartDateTime,
      endDateTime: rentalEndDateTime,
      totalAmount: fees.totalChargedAmount,
      platformFee: fees.platformFee,
      payoutAmount: fees.payoutAmount,
      paymentStatus: totalAmount > 0 ? "pending" : "not_required",
      status: "pending",
      deliveryMethod,
      deliveryAddress,
      intendedUse,
    };

    // Only add stripePaymentMethodId if it's provided (for paid rentals)
    if (stripePaymentMethodId) {
      rentalData.stripePaymentMethodId = stripePaymentMethodId;
    }

    const rental = await Rental.create(rentalData);

    const rentalWithDetails = await Rental.findByPk(rental.id, {
      include: [
        { model: Item, as: "item" },
        {
          model: User,
          as: "owner",
          attributes: ["id", "firstName", "lastName", "email"],
        },
        {
          model: User,
          as: "renter",
          attributes: ["id", "firstName", "lastName", "email"],
        },
      ],
    });

    // Send rental request notification to owner
    try {
      await emailServices.rentalFlow.sendRentalRequestEmail(
        rentalWithDetails.owner,
        rentalWithDetails.renter,
        rentalWithDetails
      );
      const reqLogger = logger.withRequestId(req.id);
      reqLogger.info("Rental request notification sent to owner", {
        rentalId: rental.id,
        ownerId: rentalWithDetails.ownerId,
      });
    } catch (emailError) {
      // Log error but don't fail the request
      const reqLogger = logger.withRequestId(req.id);
      reqLogger.error("Failed to send rental request email", {
        error: emailError.message,
        stack: emailError.stack,
        rentalId: rental.id,
        ownerId: rentalWithDetails.ownerId,
      });
    }

    // Send rental request confirmation to renter
    try {
      await emailServices.rentalFlow.sendRentalRequestConfirmationEmail(
        rentalWithDetails.renter,
        rentalWithDetails
      );
      const reqLogger = logger.withRequestId(req.id);
      reqLogger.info("Rental request confirmation sent to renter", {
        rentalId: rental.id,
        renterId: rentalWithDetails.renterId,
      });
    } catch (emailError) {
      // Log error but don't fail the request
      const reqLogger = logger.withRequestId(req.id);
      reqLogger.error("Failed to send rental request confirmation email", {
        error: emailError.message,
        stack: emailError.stack,
        rentalId: rental.id,
        renterId: rentalWithDetails.renterId,
      });
    }

    res.status(201).json(rentalWithDetails);
  } catch (error) {
    res.status(500).json({ error: "Failed to create rental" });
  }
});

router.put("/:id/status", authenticateToken, async (req, res) => {
  try {
    const { status } = req.body;
    const rental = await Rental.findByPk(req.params.id, {
      include: [
        { model: Item, as: "item" },
        {
          model: User,
          as: "owner",
          attributes: [
            "id",
            "firstName",
            "lastName",
            "email",
            "stripeConnectedAccountId",
          ],
        },
        {
          model: User,
          as: "renter",
          attributes: [
            "id",
            "firstName",
            "lastName",
            "email",
            "stripeCustomerId",
          ],
        },
      ],
    });

    if (!rental) {
      return res.status(404).json({ error: "Rental not found" });
    }

    if (rental.ownerId !== req.user.id && rental.renterId !== req.user.id) {
      return res
        .status(403)
        .json({ error: "Unauthorized to update this rental" });
    }

    // If owner is approving a pending rental, handle payment for paid rentals
    if (
      status === "confirmed" &&
      rental.status === "pending" &&
      rental.ownerId === req.user.id
    ) {
      // Skip payment processing for free rentals
      if (rental.totalAmount > 0) {
        if (!rental.stripePaymentMethodId) {
          return res
            .status(400)
            .json({ error: "No payment method found for this rental" });
        }

        try {
          // Import StripeService to process the payment
          const StripeService = require("../services/stripeService");

          // Check if renter has a stripe customer ID
          if (!rental.renter.stripeCustomerId) {
            return res.status(400).json({
              error: "Renter does not have a Stripe customer account",
            });
          }

          // Create payment intent and charge the stored payment method
          const paymentResult = await StripeService.chargePaymentMethod(
            rental.stripePaymentMethodId,
            rental.totalAmount,
            rental.renter.stripeCustomerId,
            {
              rentalId: rental.id,
              itemName: rental.item.name,
              renterId: rental.renterId,
              ownerId: rental.ownerId,
            }
          );

          // Check if 3DS authentication is required
          if (paymentResult.requiresAction) {
            // Store payment intent for later completion
            await rental.update({
              stripePaymentIntentId: paymentResult.paymentIntentId,
              paymentStatus: "requires_action",
            });

            // Send email to renter (without direct link for security)
            try {
              await emailServices.rentalFlow.sendAuthenticationRequiredEmail(
                rental.renter.email,
                {
                  renterName: rental.renter.firstName,
                  itemName: rental.item.name,
                  ownerName: rental.owner.firstName,
                  amount: rental.totalAmount,
                }
              );
              const reqLogger = logger.withRequestId(req.id);
              reqLogger.info("Authentication required email sent to renter", {
                rentalId: rental.id,
                renterId: rental.renterId,
              });
            } catch (emailError) {
              const reqLogger = logger.withRequestId(req.id);
              reqLogger.error(
                "Failed to send authentication required email",
                {
                  error: emailError.message,
                  stack: emailError.stack,
                  rentalId: rental.id,
                  renterId: rental.renterId,
                }
              );
            }

            return res.status(402).json({
              error: "authentication_required",
              requiresAction: true,
              message: "The renter's card requires additional authentication.",
              rentalId: rental.id,
            });
          }

          // Update rental with payment completion
          await rental.update({
            status: "confirmed",
            paymentStatus: "paid",
            stripePaymentIntentId: paymentResult.paymentIntentId,
            paymentMethodBrand: paymentResult.paymentMethod?.brand || null,
            paymentMethodLast4: paymentResult.paymentMethod?.last4 || null,
            chargedAt: paymentResult.chargedAt || new Date(),
          });

          const updatedRental = await Rental.findByPk(rental.id, {
            include: [
              { model: Item, as: "item" },
              {
                model: User,
                as: "owner",
                attributes: [
                  "id",
                  "firstName",
                  "lastName",
                  "email",
                  "stripeConnectedAccountId",
                ],
              },
              {
                model: User,
                as: "renter",
                attributes: ["id", "firstName", "lastName", "email"],
              },
            ],
          });

          // Create condition check reminder schedules
          try {
            await EventBridgeSchedulerService.createConditionCheckSchedules(
              updatedRental
            );
          } catch (schedulerError) {
            const reqLogger = logger.withRequestId(req.id);
            reqLogger.error(
              "Failed to create condition check schedules",
              {
                error: schedulerError.message,
                rentalId: updatedRental.id,
              }
            );
            // Don't fail the confirmation - schedules are non-critical
          }

          // Send confirmation emails
          // Send approval confirmation to owner with Stripe reminder
          try {
            await emailServices.rentalFlow.sendRentalApprovalConfirmationEmail(
              updatedRental.owner,
              updatedRental.renter,
              updatedRental
            );
            const reqLogger = logger.withRequestId(req.id);
            reqLogger.info("Rental approval confirmation sent to owner", {
              rentalId: updatedRental.id,
              ownerId: updatedRental.ownerId,
            });
          } catch (emailError) {
            const reqLogger = logger.withRequestId(req.id);
            reqLogger.error(
              "Failed to send rental approval confirmation email to owner",
              {
                error: emailError.message,
                stack: emailError.stack,
                rentalId: updatedRental.id,
                ownerId: updatedRental.ownerId,
              }
            );
          }

          // Send rental confirmation to renter with payment receipt
          try {
            const renter = await User.findByPk(updatedRental.renterId, {
              attributes: ["email", "firstName"],
            });
            if (renter) {
              const renterNotification = {
                type: "rental_confirmed",
                title: "Rental Confirmed",
                message: `Your rental of "${updatedRental.item.name}" has been confirmed.`,
                rentalId: updatedRental.id,
                userId: updatedRental.renterId,
                metadata: { rentalStart: updatedRental.startDateTime },
              };
              await emailServices.rentalFlow.sendRentalConfirmation(
                renter.email,
                renterNotification,
                updatedRental,
                renter.firstName,
                true // isRenter = true to show payment receipt
              );
              const reqLogger = logger.withRequestId(req.id);
              reqLogger.info("Rental confirmation sent to renter", {
                rentalId: updatedRental.id,
                renterId: updatedRental.renterId,
              });
            }
          } catch (emailError) {
            const reqLogger = logger.withRequestId(req.id);
            reqLogger.error(
              "Failed to send rental confirmation email to renter",
              {
                error: emailError.message,
                stack: emailError.stack,
                rentalId: updatedRental.id,
                renterId: updatedRental.renterId,
              }
            );
          }

          res.json(updatedRental);
          return;
        } catch (paymentError) {
          const reqLogger = logger.withRequestId(req.id);
          reqLogger.error("Payment failed during approval", {
            error: paymentError.message,
            code: paymentError.code,
            stack: paymentError.stack,
            rentalId: req.params.id,
            userId: req.user.id,
          });

          // Determine the renter-facing message
          const renterMessage =
            paymentError instanceof PaymentError
              ? paymentError.renterMessage
              : "Your payment could not be processed. Please try a different payment method.";

          // Track payment failure timestamp and reason
          await rental.update({
            paymentFailedNotifiedAt: new Date(),
            paymentFailedReason: renterMessage,
          });

          // Auto-send payment declined email to renter
          try {
            await emailServices.payment.sendPaymentDeclinedNotification(
              rental.renter.email,
              {
                renterFirstName: rental.renter.firstName,
                itemName: rental.item.name,
                declineReason: renterMessage,
                rentalId: rental.id,
              }
            );
            reqLogger.info("Payment declined email auto-sent to renter", {
              rentalId: rental.id,
              renterId: rental.renterId,
            });
          } catch (emailError) {
            reqLogger.error("Failed to send payment declined email", {
              error: emailError.message,
              rentalId: rental.id,
            });
          }

          // Keep rental as pending, inform owner of payment failure
          const ownerMessage =
            paymentError instanceof PaymentError
              ? paymentError.ownerMessage
              : "The payment could not be processed.";

          return res.status(402).json({
            error: "payment_failed",
            code: paymentError.code || "unknown_error",
            ownerMessage,
            renterMessage,
            rentalId: rental.id,
          });
        }
      } else {
        // For free rentals, just update status directly
        await rental.update({
          status: "confirmed",
        });

        const updatedRental = await Rental.findByPk(rental.id, {
          include: [
            { model: Item, as: "item" },
            {
              model: User,
              as: "owner",
              attributes: [
                "id",
                "firstName",
                "lastName",
                "email",
                "stripeConnectedAccountId",
              ],
            },
            {
              model: User,
              as: "renter",
              attributes: ["id", "firstName", "lastName", "email"],
            },
          ],
        });

        // Create condition check reminder schedules
        try {
          await EventBridgeSchedulerService.createConditionCheckSchedules(
            updatedRental
          );
        } catch (schedulerError) {
          const reqLogger = logger.withRequestId(req.id);
          reqLogger.error(
            "Failed to create condition check schedules",
            {
              error: schedulerError.message,
              rentalId: updatedRental.id,
            }
          );
          // Don't fail the confirmation - schedules are non-critical
        }

        // Send confirmation emails
        // Send approval confirmation to owner (for free rentals, no Stripe reminder shown)
        try {
          await emailServices.rentalFlow.sendRentalApprovalConfirmationEmail(
            updatedRental.owner,
            updatedRental.renter,
            updatedRental
          );
          const reqLogger = logger.withRequestId(req.id);
          reqLogger.info("Rental approval confirmation sent to owner", {
            rentalId: updatedRental.id,
            ownerId: updatedRental.ownerId,
          });
        } catch (emailError) {
          const reqLogger = logger.withRequestId(req.id);
          reqLogger.error(
            "Failed to send rental approval confirmation email to owner",
            {
              error: emailError.message,
              stack: emailError.stack,
              rentalId: updatedRental.id,
              ownerId: updatedRental.ownerId,
            }
          );
        }

        // Send rental confirmation to renter
        try {
          const renter = await User.findByPk(updatedRental.renterId, {
            attributes: ["email", "firstName"],
          });
          if (renter) {
            const renterNotification = {
              type: "rental_confirmed",
              title: "Rental Confirmed",
              message: `Your rental of "${updatedRental.item.name}" has been confirmed.`,
              rentalId: updatedRental.id,
              userId: updatedRental.renterId,
              metadata: { rentalStart: updatedRental.startDateTime },
            };
            await emailServices.rentalFlow.sendRentalConfirmation(
              renter.email,
              renterNotification,
              updatedRental,
              renter.firstName,
              true // isRenter = true (for free rentals, shows "no payment required")
            );
            const reqLogger = logger.withRequestId(req.id);
            reqLogger.info("Rental confirmation sent to renter", {
              rentalId: updatedRental.id,
              renterId: updatedRental.renterId,
            });
          }
        } catch (emailError) {
          const reqLogger = logger.withRequestId(req.id);
          reqLogger.error(
            "Failed to send rental confirmation email to renter",
            {
              error: emailError.message,
              stack: emailError.stack,
              rentalId: updatedRental.id,
              renterId: updatedRental.renterId,
            }
          );
        }

        res.json(updatedRental);
        return;
      }
    }

    await rental.update({ status });

    const updatedRental = await Rental.findByPk(rental.id, {
      include: [
        { model: Item, as: "item" },
        {
          model: User,
          as: "owner",
          attributes: ["id", "firstName", "lastName"],
        },
        {
          model: User,
          as: "renter",
          attributes: ["id", "firstName", "lastName"],
        },
      ],
    });

    res.json(updatedRental);
  } catch (error) {
    res.status(500).json({ error: "Failed to update rental status" });
  }
});

// Decline rental request (owner only)
router.put("/:id/decline", authenticateToken, async (req, res) => {
  try {
    const { reason } = req.body;

    // Validate that reason is provided
    if (!reason || reason.trim() === "") {
      return res.status(400).json({
        error: "A reason for declining is required",
      });
    }

    const rental = await Rental.findByPk(req.params.id, {
      include: [
        { model: Item, as: "item" },
        {
          model: User,
          as: "owner",
          attributes: ["id", "firstName", "lastName"],
        },
        {
          model: User,
          as: "renter",
          attributes: ["id", "firstName", "lastName", "email"],
        },
      ],
    });

    if (!rental) {
      return res.status(404).json({ error: "Rental not found" });
    }

    // Only owner can decline
    if (rental.ownerId !== req.user.id) {
      return res
        .status(403)
        .json({ error: "Only the item owner can decline rental requests" });
    }

    // Can only decline pending rentals
    if (rental.status !== "pending") {
      return res.status(400).json({
        error: "Can only decline pending rental requests",
      });
    }

    // Update rental status to declined
    await rental.update({
      status: "declined",
      declineReason: reason,
    });

    const updatedRental = await Rental.findByPk(rental.id, {
      include: [
        { model: Item, as: "item" },
        {
          model: User,
          as: "owner",
          attributes: ["id", "firstName", "lastName", "email"],
        },
        {
          model: User,
          as: "renter",
          attributes: ["id", "firstName", "lastName", "email"],
        },
      ],
    });

    // Send decline notification email to renter
    try {
      await emailServices.rentalFlow.sendRentalDeclinedEmail(
        updatedRental.renter,
        updatedRental,
        reason
      );
      const reqLogger = logger.withRequestId(req.id);
      reqLogger.info("Rental decline notification sent to renter", {
        rentalId: rental.id,
        renterId: updatedRental.renterId,
      });
    } catch (emailError) {
      // Log error but don't fail the request
      const reqLogger = logger.withRequestId(req.id);
      reqLogger.error("Failed to send rental decline email", {
        error: emailError.message,
        stack: emailError.stack,
        rentalId: rental.id,
        renterId: updatedRental.renterId,
      });
    }

    res.json(updatedRental);
  } catch (error) {
    const reqLogger = logger.withRequestId(req.id);
    reqLogger.error("Error declining rental", {
      error: error.message,
      stack: error.stack,
      rentalId: req.params.id,
      userId: req.user.id,
    });
    res.status(500).json({ error: "Failed to decline rental" });
  }
});

// Owner reviews renter
router.post("/:id/review-renter", authenticateToken, async (req, res) => {
  try {
    const { rating, review, privateMessage } = req.body;
    const rental = await Rental.findByPk(req.params.id);

    if (!rental) {
      return res.status(404).json({ error: "Rental not found" });
    }

    if (rental.ownerId !== req.user.id) {
      return res.status(403).json({ error: "Only owners can review renters" });
    }

    if (rental.status !== "completed") {
      return res
        .status(400)
        .json({ error: "Can only review completed rentals" });
    }

    if (rental.renterReviewSubmittedAt) {
      return res.status(400).json({ error: "Renter review already submitted" });
    }

    // Submit the review and private message
    await rental.update({
      renterRating: rating,
      renterReview: review,
      renterReviewSubmittedAt: new Date(),
      renterPrivateMessage: privateMessage,
    });

    // Check and update visibility
    const updatedRental = await checkAndUpdateReviewVisibility(rental);

    res.json({
      success: true,
      reviewVisible: updatedRental.renterReviewVisible,
    });
  } catch (error) {
    res.status(500).json({ error: "Failed to submit review" });
  }
});

// Renter reviews item
router.post("/:id/review-item", authenticateToken, async (req, res) => {
  try {
    const { rating, review, privateMessage } = req.body;
    const rental = await Rental.findByPk(req.params.id);

    if (!rental) {
      return res.status(404).json({ error: "Rental not found" });
    }

    if (rental.renterId !== req.user.id) {
      return res.status(403).json({ error: "Only renters can review items" });
    }

    if (rental.status !== "completed") {
      return res
        .status(400)
        .json({ error: "Can only review completed rentals" });
    }

    if (rental.itemReviewSubmittedAt) {
      return res.status(400).json({ error: "Item review already submitted" });
    }

    // Submit the review and private message
    await rental.update({
      itemRating: rating,
      itemReview: review,
      itemReviewSubmittedAt: new Date(),
      itemPrivateMessage: privateMessage,
    });

    // Check and update visibility
    const updatedRental = await checkAndUpdateReviewVisibility(rental);

    res.json({
      success: true,
      reviewVisible: updatedRental.itemReviewVisible,
    });
  } catch (error) {
    res.status(500).json({ error: "Failed to submit review" });
  }
});

// Calculate fees for rental pricing display
router.post("/calculate-fees", authenticateToken, async (req, res) => {
  try {
    const { totalAmount } = req.body;

    if (!totalAmount || totalAmount <= 0) {
      return res.status(400).json({ error: "Valid base amount is required" });
    }

    const fees = FeeCalculator.calculateRentalFees(totalAmount);
    const displayFees = FeeCalculator.formatFeesForDisplay(fees);

    res.json({
      fees,
      display: displayFees,
    });
  } catch (error) {
    const reqLogger = logger.withRequestId(req.id);
    reqLogger.error("Error calculating fees", {
      error: error.message,
      stack: error.stack,
      userId: req.user.id,
      startDate: req.query.startDate,
      endDate: req.query.endDate,
      itemId: req.query.itemId,
    });
    res.status(500).json({ error: "Failed to calculate fees" });
  }
});

// Preview rental cost calculation (no rental creation)
router.post("/cost-preview", authenticateToken, async (req, res) => {
  try {
    const { itemId, startDateTime, endDateTime } = req.body;

    // Validate inputs
    if (!itemId || !startDateTime || !endDateTime) {
      return res.status(400).json({
        error: "itemId, startDateTime, and endDateTime are required",
      });
    }

    // Fetch item
    const item = await Item.findByPk(itemId);
    if (!item) {
      return res.status(404).json({ error: "Item not found" });
    }

    // Parse datetimes
    const rentalStartDateTime = new Date(startDateTime);
    const rentalEndDateTime = new Date(endDateTime);

    // Validate date formats
    if (isNaN(rentalStartDateTime.getTime())) {
      return res.status(400).json({ error: "Invalid start date format" });
    }
    if (isNaN(rentalEndDateTime.getTime())) {
      return res.status(400).json({ error: "Invalid end date format" });
    }

    // Validate start date is not in the past (with 5 minute grace period)
    const now = new Date();
    const fiveMinutesAgo = new Date(now.getTime() - 5 * 60 * 1000);
    if (rentalStartDateTime < fiveMinutesAgo) {
      return res
        .status(400)
        .json({ error: "Start date cannot be in the past" });
    }

    // Validate date range
    if (rentalEndDateTime <= rentalStartDateTime) {
      return res.status(400).json({
        error: "End date/time must be after start date/time",
      });
    }

    // Check for overlapping rentals (same logic as in POST /rentals)
    // Two ranges overlap if: existingStart < newEnd AND existingEnd > newStart
    const overlappingRental = await Rental.findOne({
      where: {
        itemId,
        status: "confirmed",
        startDateTime: { [Op.not]: null },
        endDateTime: { [Op.not]: null },
        [Op.and]: [
          { startDateTime: { [Op.lt]: rentalEndDateTime } },
          { endDateTime: { [Op.gt]: rentalStartDateTime } },
        ],
      },
    });

    if (overlappingRental) {
      return res
        .status(400)
        .json({ error: "Item is already booked for these dates" });
    }

    // Calculate rental cost using duration calculator
    const totalAmount = RentalDurationCalculator.calculateRentalCost(
      rentalStartDateTime,
      rentalEndDateTime,
      item
    );

    // Calculate fees
    const fees = FeeCalculator.calculateRentalFees(totalAmount);

    res.json({
      baseAmount: totalAmount,
      fees,
    });
  } catch (error) {
    const reqLogger = logger.withRequestId(req.id);
    reqLogger.error("Error calculating rental cost preview", {
      error: error.message,
      stack: error.stack,
      userId: req.user.id,
    });
    res.status(500).json({ error: "Failed to calculate rental cost preview" });
  }
});

// Get earnings status for owner's rentals
router.get("/earnings/status", authenticateToken, async (req, res, next) => {
  const reqLogger = logger.withRequestId(req.id);

  try {
    // Trigger payout reconciliation in background (non-blocking)
    // This catches any missed payout.paid or payout.failed webhooks
    StripeWebhookService.reconcilePayoutStatuses(req.user.id).catch((err) => {
      reqLogger.error("Background payout reconciliation failed", {
        error: err.message,
        userId: req.user.id,
      });
    });

    const ownerRentals = await Rental.findAll({
      where: {
        ownerId: req.user.id,
        status: "completed",
      },
      attributes: [
        "id",
        "totalAmount",
        "platformFee",
        "payoutAmount",
        "payoutStatus",
        "payoutProcessedAt",
        "stripeTransferId",
        "bankDepositStatus",
        "bankDepositAt",
        "bankDepositFailureCode",
      ],
      include: [{ model: Item, as: "item", attributes: ["name"] }],
      order: [["createdAt", "DESC"]],
    });

    res.json(ownerRentals);
  } catch (error) {
    reqLogger.error("Error getting earnings status", {
      error: error.message,
      stack: error.stack,
      userId: req.user.id,
    });
    next(error);
  }
});

// Get refund preview (what would happen if cancelled now)
router.get("/:id/refund-preview", authenticateToken, async (req, res, next) => {
  try {
    const preview = await RefundService.getRefundPreview(
      req.params.id,
      req.user.id
    );
    res.json(preview);
  } catch (error) {
    const reqLogger = logger.withRequestId(req.id);
    reqLogger.error("Error getting refund preview", {
      error: error.message,
      stack: error.stack,
      rentalId: req.params.id,
      userId: req.user.id,
    });
    next(error);
  }
});

// Get late fee preview
router.get(
  "/:id/late-fee-preview",
  authenticateToken,
  async (req, res, next) => {
    try {
      const { actualReturnDateTime } = req.query;

      if (!actualReturnDateTime) {
        return res
          .status(400)
          .json({ error: "actualReturnDateTime is required" });
      }

      const rental = await Rental.findByPk(req.params.id, {
        include: [{ model: Item, as: "item" }],
      });

      if (!rental) {
        return res.status(404).json({ error: "Rental not found" });
      }

      // Check authorization
      if (rental.ownerId !== req.user.id && rental.renterId !== req.user.id) {
        return res.status(403).json({ error: "Unauthorized" });
      }

      const lateCalculation = LateReturnService.calculateLateFee(
        rental,
        actualReturnDateTime
      );

      res.json(lateCalculation);
    } catch (error) {
      const reqLogger = logger.withRequestId(req.id);
      reqLogger.error("Error getting late fee preview", {
        error: error.message,
        stack: error.stack,
        rentalId: req.params.id,
        userId: req.user.id,
      });
      next(error);
    }
  }
);

// Cancel rental with refund processing
router.post("/:id/cancel", authenticateToken, async (req, res, next) => {
  try {
    const { reason } = req.body;

    // Validate that reason is provided
    if (!reason || !reason.trim()) {
      return res.status(400).json({ error: "Cancellation reason is required" });
    }

    const result = await RefundService.processCancellation(
      req.params.id,
      req.user.id,
      reason.trim()
    );

    // Return the updated rental with refund information
    const updatedRental = await Rental.findByPk(result.rental.id, {
      include: [
        { model: Item, as: "item" },
        {
          model: User,
          as: "owner",
          attributes: ["id", "firstName", "lastName", "email"],
        },
        {
          model: User,
          as: "renter",
          attributes: ["id", "firstName", "lastName", "email"],
        },
      ],
    });

    // Send cancellation notification emails
    try {
      await emailServices.rentalFlow.sendRentalCancellationEmails(
        updatedRental.owner,
        updatedRental.renter,
        updatedRental,
        result.refund
      );
      const reqLogger = logger.withRequestId(req.id);
      reqLogger.info("Cancellation emails sent", {
        rentalId: updatedRental.id,
        cancelledBy: updatedRental.cancelledBy,
      });
    } catch (emailError) {
      // Log error but don't fail the request
      const reqLogger = logger.withRequestId(req.id);
      reqLogger.error("Failed to send cancellation emails", {
        error: emailError.message,
        stack: emailError.stack,
        rentalId: updatedRental.id,
        cancelledBy: updatedRental.cancelledBy,
      });
    }

    res.json({
      rental: updatedRental,
      refund: result.refund,
    });
  } catch (error) {
    const reqLogger = logger.withRequestId(req.id);
    reqLogger.error("Error cancelling rental", {
      error: error.message,
      stack: error.stack,
      rentalId: req.params.id,
      userId: req.user.id,
    });
    next(error);
  }
});

// Mark item return status (owner only)
router.post("/:id/mark-return", authenticateToken, async (req, res, next) => {
  try {
    const { status, actualReturnDateTime, statusOptions } = req.body;
    const rentalId = req.params.id;
    const userId = req.user.id;

    const rental = await Rental.findByPk(rentalId, {
      include: [{ model: Item, as: "item" }],
    });

    if (!rental) {
      return res.status(404).json({ error: "Rental not found" });
    }

    if (rental.ownerId !== userId) {
      return res
        .status(403)
        .json({ error: "Only the item owner can mark return status" });
    }

    if (!isActive(rental)) {
      return res.status(400).json({
        error: "Can only mark return status for active rentals",
      });
    }

    let updatedRental;
    let additionalInfo = {};

    switch (status) {
      case "returned":
        // Item returned on time
        updatedRental = await rental.update({
          status: "completed",
          payoutStatus: "pending",
          actualReturnDateTime: actualReturnDateTime || rental.endDateTime,
        });

        // Fetch full rental details with associations for email
        const rentalWithDetails = await Rental.findByPk(rentalId, {
          include: [
            { model: Item, as: "item" },
            {
              model: User,
              as: "owner",
              attributes: [
                "id",
                "firstName",
                "lastName",
                "email",
                "stripeConnectedAccountId",
              ],
            },
            {
              model: User,
              as: "renter",
              attributes: ["id", "firstName", "lastName", "email"],
            },
          ],
        });

        // Send completion emails to both renter and owner
        try {
          await emailServices.rentalFlow.sendRentalCompletionEmails(
            rentalWithDetails.owner,
            rentalWithDetails.renter,
            rentalWithDetails
          );
          const reqLogger = logger.withRequestId(req.id);
          reqLogger.info("Rental completion emails sent", {
            rentalId,
            ownerId: rental.ownerId,
            renterId: rental.renterId,
          });
        } catch (emailError) {
          const reqLogger = logger.withRequestId(req.id);
          reqLogger.error("Failed to send rental completion emails", {
            error: emailError.message,
            stack: emailError.stack,
            rentalId,
          });
        }

        // Trigger immediate payout attempt (non-blocking)
        PayoutService.triggerPayoutOnCompletion(rentalId).catch((err) => {
          logger.error("Error triggering payout on mark-return", {
            rentalId,
            error: err.message,
          });
        });
        break;

      case "damaged":
        // Item returned damaged
        const damageUpdates = {
          status: "damaged",
          payoutStatus: "pending",
          actualReturnDateTime: actualReturnDateTime || rental.endDateTime,
        };

        // Check if ALSO returned late
        if (statusOptions?.returned_late && actualReturnDateTime) {
          const lateReturnDamaged = await LateReturnService.processLateReturn(
            rentalId,
            actualReturnDateTime
          );
          damageUpdates.status = "returned_late_and_damaged";
          damageUpdates.lateFees = lateReturnDamaged.lateCalculation.lateFee;
          damageUpdates.actualReturnDateTime =
            lateReturnDamaged.rental.actualReturnDateTime;
          additionalInfo.lateCalculation = lateReturnDamaged.lateCalculation;
        }

        updatedRental = await rental.update(damageUpdates);
        break;

      case "returned_late":
        // Item returned late - calculate late fees
        if (!actualReturnDateTime) {
          return res.status(400).json({
            error: "Actual return date/time is required for late returns",
          });
        }

        const lateReturn = await LateReturnService.processLateReturn(
          rentalId,
          actualReturnDateTime
        );

        updatedRental = lateReturn.rental;
        additionalInfo.lateCalculation = lateReturn.lateCalculation;
        break;

      case "lost":
        // Item reported as lost
        updatedRental = await rental.update({
          status: "lost",
          payoutStatus: "pending",
          itemLostReportedAt: new Date(),
        });

        // Send notification to customer service
        const owner = await User.findByPk(rental.ownerId);
        const renter = await User.findByPk(rental.renterId);
        await emailServices.customerService.sendLostItemToCustomerService(
          updatedRental,
          owner,
          renter
        );
        break;

      default:
        return res.status(400).json({
          error:
            "Invalid status. Use 'returned', 'returned_late', 'damaged', or 'lost'",
        });
    }

    const reqLogger = logger.withRequestId(req.id);
    reqLogger.info("Return status marked", {
      rentalId,
      status,
      ownerId: userId,
      lateFee: updatedRental.lateFees || 0,
    });

    res.json({
      success: true,
      rental: updatedRental,
      ...additionalInfo,
    });
  } catch (error) {
    const reqLogger = logger.withRequestId(req.id);
    reqLogger.error("Error marking return status", {
      error: error.message,
      stack: error.stack,
      rentalId: req.params.id,
      userId: req.user.id,
    });

    next(error);
  }
});

// Allowed fields for damage report (prevents mass assignment)
const ALLOWED_DAMAGE_REPORT_FIELDS = [
  "description",
  "canBeFixed",
  "repairCost",
  "needsReplacement",
  "replacementCost",
  "proofOfOwnership",
  "actualReturnDateTime",
  "imageFilenames",
];

function extractAllowedDamageFields(body) {
  const result = {};
  for (const field of ALLOWED_DAMAGE_REPORT_FIELDS) {
    if (body[field] !== undefined) {
      result[field] = body[field];
    }
  }
  return result;
}

// Report item as damaged (owner only)
router.post("/:id/report-damage", authenticateToken, async (req, res, next) => {
  try {
    const rentalId = req.params.id;
    const userId = req.user.id;
    // Extract only allowed fields (prevents mass assignment)
    const damageInfo = extractAllowedDamageFields(req.body);

    // Validate imageFilenames if provided
    if (damageInfo.imageFilenames !== undefined) {
      const imageFilenamesArray = Array.isArray(damageInfo.imageFilenames)
        ? damageInfo.imageFilenames
        : [];

      const keyValidation = validateS3Keys(
        imageFilenamesArray,
        "damage-reports",
        {
          maxKeys: IMAGE_LIMITS.damageReports,
        }
      );
      if (!keyValidation.valid) {
        return res.status(400).json({
          error: keyValidation.error,
          details: keyValidation.invalidKeys,
        });
      }
      damageInfo.imageFilenames = imageFilenamesArray;
    }

    const result = await DamageAssessmentService.processDamageAssessment(
      rentalId,
      damageInfo,
      userId
    );

    const reqLogger = logger.withRequestId(req.id);
    reqLogger.info("Damage reported", {
      rentalId,
      ownerId: userId,
      damageFee: result.damageAssessment.feeCalculation.amount,
      lateFee: result.lateCalculation?.lateFee || 0,
    });

    res.json({
      success: true,
      ...result,
    });
  } catch (error) {
    const reqLogger = logger.withRequestId(req.id);
    reqLogger.error("Error reporting damage", {
      error: error.message,
      stack: error.stack,
      rentalId: req.params.id,
      userId: req.user.id,
    });

    next(error);
  }
});

// PUT /rentals/:id/payment-method - Renter updates payment method for pending rental
router.put("/:id/payment-method", authenticateToken, async (req, res, next) => {
  try {
    const rentalId = req.params.id;
    const { stripePaymentMethodId } = req.body;

    if (!stripePaymentMethodId) {
      return res.status(400).json({ error: "Payment method ID is required" });
    }

    const rental = await Rental.findByPk(rentalId, {
      include: [
        { model: Item, as: "item" },
        {
          model: User,
          as: "owner",
          attributes: ["id", "firstName", "email"],
        },
      ],
    });

    if (!rental) {
      return res.status(404).json({ error: "Rental not found" });
    }

    // Only renter can update payment method
    if (rental.renterId !== req.user.id) {
      return res
        .status(403)
        .json({ error: "Only the renter can update the payment method" });
    }

    // Only for pending rentals with pending payment
    if (rental.status !== "pending" || rental.paymentStatus !== "pending") {
      return res.status(400).json({
        error: "Can only update payment method for pending rentals",
      });
    }

    // Verify payment method belongs to renter's Stripe customer
    const renter = await User.findByPk(req.user.id);
    if (!renter.stripeCustomerId) {
      return res
        .status(400)
        .json({ error: "No Stripe customer account found" });
    }

    let paymentMethod;
    try {
      paymentMethod = await StripeService.getPaymentMethod(
        stripePaymentMethodId
      );
    } catch {
      return res.status(400).json({ error: "Invalid payment method" });
    }

    if (paymentMethod.customer !== renter.stripeCustomerId) {
      return res
        .status(403)
        .json({ error: "Payment method does not belong to this account" });
    }

    // Rate limiting: Max 3 updates per rental per hour
    const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000);
    if (
      rental.paymentMethodUpdatedAt &&
      rental.paymentMethodUpdatedAt > oneHourAgo
    ) {
      const updateCount = rental.paymentMethodUpdateCount || 0;
      if (updateCount >= 3) {
        return res.status(429).json({
          error: "Too many payment method updates. Please try again later.",
        });
      }
    }

    // Store old payment method for audit log
    const oldPaymentMethodId = rental.stripePaymentMethodId;

    // Atomic update with status check (prevents race condition)
    const [updateCount] = await Rental.update(
      {
        stripePaymentMethodId,
        paymentMethodUpdatedAt: new Date(),
        paymentMethodUpdateCount:
          rental.paymentMethodUpdatedAt > oneHourAgo
            ? (rental.paymentMethodUpdateCount || 0) + 1
            : 1,
      },
      {
        where: {
          id: rentalId,
          status: "pending",
          paymentStatus: "pending",
        },
      }
    );

    if (updateCount === 0) {
      return res.status(409).json({
        error: "Rental status changed. Please refresh and try again.",
      });
    }

    const reqLogger = logger.withRequestId(req.id);
    reqLogger.info("Payment method updated", {
      rentalId,
      userId: req.user.id,
      oldPaymentMethodId,
      newPaymentMethodId: stripePaymentMethodId,
    });

    // Optionally notify owner that payment method was updated
    try {
      await emailServices.payment.sendPaymentMethodUpdatedNotification(
        rental.owner.email,
        {
          ownerFirstName: rental.owner.firstName,
          itemName: rental.item.name,
          rentalId: rental.id,
          approvalUrl: `${process.env.FRONTEND_URL}/rentals/${rentalId}`,
        }
      );
    } catch (emailError) {
      // Don't fail the request if email fails
      reqLogger.error("Failed to send payment method updated notification", {
        error: emailError.message,
        rentalId,
      });
    }

    res.json({
      success: true,
      message: "Payment method updated. The owner can now retry approval.",
    });
  } catch (error) {
    const reqLogger = logger.withRequestId(req.id);
    reqLogger.error("Error updating payment method", {
      error: error.message,
      stack: error.stack,
      rentalId: req.params.id,
      userId: req.user.id,
    });

    next(error);
  }
});

/**
 * GET /rentals/:id/payment-client-secret
 * Returns client secret for 3DS completion (renter only)
 */
router.get(
  "/:id/payment-client-secret",
  authenticateToken,
  async (req, res, next) => {
    try {
      const rental = await Rental.findByPk(req.params.id, {
        include: [
          { model: User, as: "renter", attributes: ["id", "stripeCustomerId"] },
        ],
      });

      if (!rental) {
        return res.status(404).json({ error: "Rental not found" });
      }

      if (rental.renterId !== req.user.id) {
        return res.status(403).json({ error: "Not authorized" });
      }

      if (!rental.stripePaymentIntentId) {
        return res.status(400).json({ error: "No payment intent found" });
      }

      const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY);
      const paymentIntent = await stripe.paymentIntents.retrieve(
        rental.stripePaymentIntentId
      );

      return res.json({
        clientSecret: paymentIntent.client_secret,
        status: paymentIntent.status,
      });
    } catch (error) {
      const reqLogger = logger.withRequestId(req.id);
      reqLogger.error("Get client secret error", {
        error: error.message,
        stack: error.stack,
        rentalId: req.params.id,
        userId: req.user.id,
      });
      next(error);
    }
  }
);

/**
 * POST /rentals/:id/complete-payment
 * Called after renter completes 3DS authentication
 */
router.post(
  "/:id/complete-payment",
  authenticateToken,
  async (req, res, next) => {
    try {
      const rental = await Rental.findByPk(req.params.id, {
        include: [
          { model: User, as: "renter", attributes: ["id", "firstName", "lastName", "email", "stripeCustomerId"] },
          { model: User, as: "owner", attributes: ["id", "firstName", "lastName", "email", "stripeConnectedAccountId", "stripePayoutsEnabled"] },
          { model: Item, as: "item" },
        ],
      });

      if (!rental) {
        return res.status(404).json({ error: "Rental not found" });
      }

      if (rental.renterId !== req.user.id) {
        return res.status(403).json({ error: "Not authorized" });
      }

      if (rental.paymentStatus !== "requires_action") {
        return res.status(400).json({
          error: "Invalid state",
          message: "This rental is not awaiting payment authentication",
        });
      }

      // Retrieve payment intent to check status (expand latest_charge for payment method details)
      const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY);
      const paymentIntent = await stripe.paymentIntents.retrieve(
        rental.stripePaymentIntentId,
        { expand: ['latest_charge.payment_method_details'] }
      );

      if (paymentIntent.status !== "succeeded") {
        return res.status(402).json({
          error: "payment_incomplete",
          status: paymentIntent.status,
          message:
            paymentIntent.status === "requires_action"
              ? "Authentication not yet completed"
              : "Payment could not be completed",
        });
      }

      // Extract payment method details from latest_charge (charges is deprecated)
      const charge = paymentIntent.latest_charge;
      const paymentMethodDetails = charge?.payment_method_details;

      let paymentMethodBrand = null;
      let paymentMethodLast4 = null;
      if (paymentMethodDetails) {
        const type = paymentMethodDetails.type;
        if (type === "card") {
          paymentMethodBrand = paymentMethodDetails.card?.brand || "card";
          paymentMethodLast4 = paymentMethodDetails.card?.last4 || null;
        } else if (type === "us_bank_account") {
          paymentMethodBrand = "bank_account";
          paymentMethodLast4 = paymentMethodDetails.us_bank_account?.last4 || null;
        }
      }

      // Payment succeeded - complete rental confirmation
      await rental.update({
        status: "confirmed",
        paymentStatus: "paid",
        chargedAt: new Date(),
        paymentMethodBrand,
        paymentMethodLast4,
      });

      // Create condition check reminder schedules
      try {
        await EventBridgeSchedulerService.createConditionCheckSchedules(rental);
      } catch (schedulerError) {
        const reqLogger = logger.withRequestId(req.id);
        reqLogger.error(
          "Failed to create condition check schedules",
          {
            error: schedulerError.message,
            rentalId: rental.id,
          }
        );
        // Don't fail the confirmation - schedules are non-critical
      }

      // Send confirmation emails
      try {
        await emailServices.rentalFlow.sendRentalApprovalConfirmationEmail(
          rental.owner,
          rental.renter,
          rental
        );
        const reqLogger = logger.withRequestId(req.id);
        reqLogger.info("Rental approval confirmation sent to owner (after 3DS)", {
          rentalId: rental.id,
          ownerId: rental.ownerId,
        });
      } catch (emailError) {
        const reqLogger = logger.withRequestId(req.id);
        reqLogger.error(
          "Failed to send rental approval confirmation email after 3DS",
          {
            error: emailError.message,
            rentalId: rental.id,
          }
        );
      }

      try {
        const renterNotification = {
          type: "rental_confirmed",
          title: "Rental Confirmed",
          message: `Your rental of "${rental.item.name}" has been confirmed.`,
          rentalId: rental.id,
          userId: rental.renterId,
          metadata: { rentalStart: rental.startDateTime },
        };
        await emailServices.rentalFlow.sendRentalConfirmation(
          rental.renter.email,
          renterNotification,
          rental,
          rental.renter.firstName,
          true
        );
        const reqLogger = logger.withRequestId(req.id);
        reqLogger.info("Rental confirmation sent to renter (after 3DS)", {
          rentalId: rental.id,
          renterId: rental.renterId,
        });
      } catch (emailError) {
        const reqLogger = logger.withRequestId(req.id);
        reqLogger.error(
          "Failed to send rental confirmation email after 3DS",
          {
            error: emailError.message,
            rentalId: rental.id,
          }
        );
      }

      // Trigger payout if owner has payouts enabled
      if (rental.owner.stripePayoutsEnabled && rental.owner.stripeConnectedAccountId) {
        try {
          await PayoutService.processRentalPayout(rental);
          const reqLogger = logger.withRequestId(req.id);
          reqLogger.info("Payout processed after 3DS completion", {
            rentalId: rental.id,
            ownerId: rental.ownerId,
          });
        } catch (payoutError) {
          const reqLogger = logger.withRequestId(req.id);
          reqLogger.error("Payout failed after 3DS completion", {
            error: payoutError.message,
            rentalId: rental.id,
          });
        }
      }

      return res.json({
        success: true,
        rental: {
          id: rental.id,
          status: "confirmed",
          paymentStatus: "paid",
        },
      });
    } catch (error) {
      const reqLogger = logger.withRequestId(req.id);
      reqLogger.error("Complete payment error", {
        error: error.message,
        stack: error.stack,
        rentalId: req.params.id,
        userId: req.user.id,
      });
      next(error);
    }
  }
);

module.exports = router;
