const { logger, stripe, email } = require("../shared");
const queries = require("./queries");
const path = require("path");

/**
 * Process all failed payouts by retrying them.
 * This is the main handler logic invoked by the Lambda.
 * @returns {Promise<Object>} Results summary with successful and failed counts
 */
async function processPayoutRetries() {
  logger.info("Starting payout retry process");

  // Get all failed payouts with eligible owners
  const failedPayouts = await queries.getFailedPayoutsWithOwners();

  logger.info("Found failed payouts to retry", {
    count: failedPayouts.length,
  });

  if (failedPayouts.length === 0) {
    return {
      success: true,
      totalProcessed: 0,
      successful: [],
      failed: [],
      message: "No failed payouts to retry",
    };
  }

  const results = {
    successful: [],
    failed: [],
  };

  // Process each failed payout
  for (const rental of failedPayouts) {
    try {
      logger.info("Processing payout retry", {
        rentalId: rental.id,
        ownerId: rental.ownerId,
        amount: rental.payoutAmount,
      });

      // Reset to pending before retry attempt
      await queries.resetPayoutToPending(rental.id);

      // Attempt to create Stripe transfer
      const transfer = await stripe.createTransfer({
        amount: rental.payoutAmount,
        destination: rental.owner.stripeConnectedAccountId,
        metadata: {
          rentalId: rental.id,
          ownerId: rental.ownerId,
          totalAmount: rental.totalAmount.toString(),
          platformFee: rental.platformFee.toString(),
          startDateTime: rental.startDateTime.toISOString(),
          endDateTime: rental.endDateTime.toISOString(),
          retryAttempt: "true",
        },
      });

      // Update rental with successful payout
      await queries.updatePayoutSuccess(rental.id, transfer.id);

      logger.info("Payout retry successful", {
        rentalId: rental.id,
        transferId: transfer.id,
        amount: rental.payoutAmount,
      });

      // Send success email notification
      try {
        await sendPayoutSuccessEmail(rental, transfer.id);
      } catch (emailError) {
        // Log error but don't fail the payout
        logger.error("Failed to send payout success email", {
          error: emailError.message,
          rentalId: rental.id,
        });
      }

      results.successful.push({
        rentalId: rental.id,
        amount: rental.payoutAmount,
        transferId: transfer.id,
      });
    } catch (error) {
      logger.error("Payout retry failed", {
        error: error.message,
        rentalId: rental.id,
        ownerId: rental.ownerId,
      });

      // Update payout status back to failed
      await queries.updatePayoutFailed(rental.id);

      // Check if account is disconnected
      if (stripe.isAccountDisconnectedError(error)) {
        logger.warn("Account appears disconnected, cleaning up", {
          accountId: rental.owner.stripeConnectedAccountId,
        });
        await handleDisconnectedAccount(rental.owner.stripeConnectedAccountId);
      }

      results.failed.push({
        rentalId: rental.id,
        error: error.message,
      });
    }
  }

  const summary = {
    success: true,
    totalProcessed: failedPayouts.length,
    successfulCount: results.successful.length,
    failedCount: results.failed.length,
    successful: results.successful,
    failed: results.failed,
  };

  logger.info("Payout retry process complete", {
    totalProcessed: summary.totalProcessed,
    successful: summary.successfulCount,
    failed: summary.failedCount,
  });

  return summary;
}

/**
 * Send payout success email to owner.
 * @param {Object} rental - Rental object with owner and item
 * @param {string} stripeTransferId - The Stripe transfer ID
 */
async function sendPayoutSuccessEmail(rental, stripeTransferId) {
  const templatePath = path.join(
    __dirname,
    "templates",
    "payoutReceivedToOwner.html"
  );
  const template = await email.loadTemplate(templatePath);

  const ownerName = rental.owner.firstName || rental.owner.lastName || "there";
  const frontendUrl = process.env.FRONTEND_URL;

  const variables = {
    ownerName,
    payoutAmount: rental.payoutAmount.toFixed(2),
    itemName: rental.item.name,
    startDate: email.formatEmailDate(rental.startDateTime),
    endDate: email.formatEmailDate(rental.endDateTime),
    stripeTransferId,
    totalAmount: rental.totalAmount.toFixed(2),
    platformFee: rental.platformFee.toFixed(2),
    earningsDashboardUrl: `${frontendUrl}/dashboard/earnings`,
  };

  const htmlBody = email.renderTemplate(template, variables);

  await email.sendEmail(
    rental.owner.email,
    "Your earnings have been deposited - Village Share",
    htmlBody
  );
}

/**
 * Handle cleanup when a Stripe account is detected as disconnected.
 * @param {string} stripeConnectedAccountId - The disconnected account ID
 */
async function handleDisconnectedAccount(stripeConnectedAccountId) {
  try {
    const user = await queries.clearDisconnectedAccount(
      stripeConnectedAccountId
    );

    if (user) {
      logger.info("Cleaned up disconnected Stripe account", {
        userId: user.id,
        accountId: stripeConnectedAccountId,
      });
    }
  } catch (error) {
    logger.error("Failed to clean up disconnected account", {
      accountId: stripeConnectedAccountId,
      error: error.message,
    });
  }
}

module.exports = {
  processPayoutRetries,
};
