const EmailClient = require("../core/EmailClient");
const TemplateManager = require("../core/TemplateManager");
const { formatEmailDate } = require("../core/emailUtils");
const logger = require("../../../utils/logger");

/**
 * PaymentEmailService handles payment-related emails
 * This service is responsible for:
 * - Sending payment declined notifications to renters
 * - Sending payment method updated notifications to owners
 */
class PaymentEmailService {
  constructor() {
    this.emailClient = new EmailClient();
    this.templateManager = new TemplateManager();
    this.initialized = false;
  }

  /**
   * Initialize the payment email service
   * @returns {Promise<void>}
   */
  async initialize() {
    if (this.initialized) return;

    await Promise.all([
      this.emailClient.initialize(),
      this.templateManager.initialize(),
    ]);

    this.initialized = true;
    logger.info("Payment Email Service initialized successfully");
  }

  /**
   * Send payment declined notification to renter
   * @param {string} renterEmail - Renter's email address
   * @param {Object} params - Email parameters
   * @param {string} params.renterFirstName - Renter's first name
   * @param {string} params.itemName - Item name
   * @param {string} params.declineReason - User-friendly decline reason
   * @param {string} params.rentalId - Rental ID
   * @param {string} params.updatePaymentUrl - URL to update payment method
   * @returns {Promise<{success: boolean, messageId?: string, error?: string}>}
   */
  async sendPaymentDeclinedNotification(renterEmail, params) {
    if (!this.initialized) {
      await this.initialize();
    }

    try {
      const {
        renterFirstName,
        itemName,
        declineReason,
        updatePaymentUrl,
      } = params;

      const variables = {
        renterFirstName: renterFirstName || "there",
        itemName: itemName || "the item",
        declineReason: declineReason || "Your payment could not be processed.",
        updatePaymentUrl: updatePaymentUrl,
      };

      const htmlContent = await this.templateManager.renderTemplate(
        "paymentDeclinedToRenter",
        variables
      );

      return await this.emailClient.sendEmail(
        renterEmail,
        `Action Required: Payment Issue - ${itemName || "Your Rental"}`,
        htmlContent
      );
    } catch (error) {
      logger.error("Failed to send payment declined notification", { error });
      return { success: false, error: error.message };
    }
  }

  /**
   * Send payment method updated notification to owner
   * @param {string} ownerEmail - Owner's email address
   * @param {Object} params - Email parameters
   * @param {string} params.ownerFirstName - Owner's first name
   * @param {string} params.itemName - Item name
   * @param {string} params.rentalId - Rental ID
   * @param {string} params.approvalUrl - URL to approve the rental
   * @returns {Promise<{success: boolean, messageId?: string, error?: string}>}
   */
  async sendPaymentMethodUpdatedNotification(ownerEmail, params) {
    if (!this.initialized) {
      await this.initialize();
    }

    try {
      const { ownerFirstName, itemName, approvalUrl } = params;

      const variables = {
        ownerFirstName: ownerFirstName || "there",
        itemName: itemName || "the item",
        approvalUrl: approvalUrl,
      };

      const htmlContent = await this.templateManager.renderTemplate(
        "paymentMethodUpdatedToOwner",
        variables
      );

      return await this.emailClient.sendEmail(
        ownerEmail,
        `Payment Method Updated - ${itemName || "Your Item"}`,
        htmlContent
      );
    } catch (error) {
      logger.error("Failed to send payment method updated notification", { error });
      return { success: false, error: error.message };
    }
  }

  /**
   * Send payout failed notification to owner
   * @param {string} ownerEmail - Owner's email address
   * @param {Object} params - Email parameters
   * @param {string} params.ownerName - Owner's name
   * @param {number} params.payoutAmount - Payout amount in dollars
   * @param {string} params.failureMessage - User-friendly failure message
   * @param {string} params.actionRequired - Action the owner needs to take
   * @param {string} params.failureCode - The Stripe failure code
   * @param {boolean} params.requiresBankUpdate - Whether bank account update is needed
   * @param {string} params.payoutSettingsUrl - URL to payout settings
   * @returns {Promise<{success: boolean, messageId?: string, error?: string}>}
   */
  async sendPayoutFailedNotification(ownerEmail, params) {
    if (!this.initialized) {
      await this.initialize();
    }

    try {
      const {
        ownerName,
        payoutAmount,
        failureMessage,
        actionRequired,
        failureCode,
        requiresBankUpdate,
        payoutSettingsUrl,
      } = params;

      const variables = {
        ownerName: ownerName || "there",
        payoutAmount: payoutAmount?.toFixed(2) || "0.00",
        failureMessage: failureMessage || "There was an issue with your payout.",
        actionRequired: actionRequired || "Please check your bank account details.",
        failureCode: failureCode || "unknown",
        requiresBankUpdate: requiresBankUpdate || false,
        payoutSettingsUrl: payoutSettingsUrl || process.env.FRONTEND_URL + "/settings/payouts",
      };

      const htmlContent = await this.templateManager.renderTemplate(
        "payoutFailedToOwner",
        variables
      );

      return await this.emailClient.sendEmail(
        ownerEmail,
        "Action Required: Payout Issue - Village Share",
        htmlContent
      );
    } catch (error) {
      logger.error("Failed to send payout failed notification", { error });
      return { success: false, error: error.message };
    }
  }

  /**
   * Send notification when owner disconnects their Stripe account
   * @param {string} ownerEmail - Owner's email address
   * @param {Object} params - Email parameters
   * @param {string} params.ownerName - Owner's name
   * @param {boolean} params.hasPendingPayouts - Whether there are pending payouts
   * @param {number} params.pendingPayoutCount - Number of pending payouts
   * @returns {Promise<{success: boolean, messageId?: string, error?: string}>}
   */
  async sendAccountDisconnectedEmail(ownerEmail, params) {
    if (!this.initialized) {
      await this.initialize();
    }

    try {
      const { ownerName, hasPendingPayouts, pendingPayoutCount } = params;

      const variables = {
        ownerName: ownerName || "there",
        hasPendingPayouts: hasPendingPayouts || false,
        pendingPayoutCount: pendingPayoutCount || 0,
        reconnectUrl: `${process.env.FRONTEND_URL}/settings/payouts`,
      };

      const htmlContent = await this.templateManager.renderTemplate(
        "accountDisconnectedToOwner",
        variables
      );

      return await this.emailClient.sendEmail(
        ownerEmail,
        "Your payout account has been disconnected - Village Share",
        htmlContent
      );
    } catch (error) {
      logger.error("Failed to send account disconnected email", { error });
      return { success: false, error: error.message };
    }
  }

  /**
   * Send notification when owner's payouts are disabled due to requirements
   * @param {string} ownerEmail - Owner's email address
   * @param {Object} params - Email parameters
   * @param {string} params.ownerName - Owner's name
   * @param {string} params.disabledReason - Human-readable reason for disabling
   * @returns {Promise<{success: boolean, messageId?: string, error?: string}>}
   */
  async sendPayoutsDisabledEmail(ownerEmail, params) {
    if (!this.initialized) {
      await this.initialize();
    }

    try {
      const { ownerName, disabledReason } = params;

      const variables = {
        ownerName: ownerName || "there",
        disabledReason:
          disabledReason ||
          "Additional verification is required for your account.",
        earningsUrl: `${process.env.FRONTEND_URL}/earnings`,
      };

      const htmlContent = await this.templateManager.renderTemplate(
        "payoutsDisabledToOwner",
        variables
      );

      return await this.emailClient.sendEmail(
        ownerEmail,
        "Action Required: Your payouts have been paused - Village Share",
        htmlContent
      );
    } catch (error) {
      logger.error("Failed to send payouts disabled email", { error });
      return { success: false, error: error.message };
    }
  }

  /**
   * Send dispute alert to platform admin
   * Called when a new dispute is opened
   * @param {Object} disputeData - Dispute information
   * @param {string} disputeData.rentalId - Rental ID
   * @param {number} disputeData.amount - Disputed amount in dollars
   * @param {string} disputeData.reason - Stripe dispute reason code
   * @param {Date} disputeData.evidenceDueBy - Evidence submission deadline
   * @param {string} disputeData.renterEmail - Renter's email
   * @param {string} disputeData.renterName - Renter's name
   * @param {string} disputeData.ownerEmail - Owner's email
   * @param {string} disputeData.ownerName - Owner's name
   * @param {string} disputeData.itemName - Item name
   * @returns {Promise<{success: boolean, messageId?: string, error?: string}>}
   */
  async sendDisputeAlertEmail(disputeData) {
    if (!this.initialized) {
      await this.initialize();
    }

    try {
      const variables = {
        rentalId: disputeData.rentalId,
        itemName: disputeData.itemName || "Unknown Item",
        amount: disputeData.amount.toFixed(2),
        reason: this.formatDisputeReason(disputeData.reason),
        evidenceDueBy: formatEmailDate(disputeData.evidenceDueBy),
        renterName: disputeData.renterName || "Unknown",
        renterEmail: disputeData.renterEmail || "Unknown",
        ownerName: disputeData.ownerName || "Unknown",
        ownerEmail: disputeData.ownerEmail || "Unknown",
      };

      const htmlContent = await this.templateManager.renderTemplate(
        "disputeAlertToAdmin",
        variables
      );

      // Send to admin email (configure in env)
      const adminEmail = process.env.ADMIN_EMAIL || process.env.SES_FROM_EMAIL;

      return await this.emailClient.sendEmail(
        adminEmail,
        `URGENT: Payment Dispute - Rental #${disputeData.rentalId}`,
        htmlContent
      );
    } catch (error) {
      logger.error("Failed to send dispute alert email", { error });
      return { success: false, error: error.message };
    }
  }

  /**
   * Send alert when dispute is lost and owner was already paid
   * Flags for manual review to decide on potential clawback
   * @param {Object} disputeData - Dispute information
   * @param {string} disputeData.rentalId - Rental ID
   * @param {number} disputeData.amount - Lost dispute amount in dollars
   * @param {number} disputeData.ownerPayoutAmount - Amount already paid to owner
   * @param {string} disputeData.ownerEmail - Owner's email
   * @param {string} disputeData.ownerName - Owner's name
   * @returns {Promise<{success: boolean, messageId?: string, error?: string}>}
   */
  async sendDisputeLostAlertEmail(disputeData) {
    if (!this.initialized) {
      await this.initialize();
    }

    try {
      const variables = {
        rentalId: disputeData.rentalId,
        amount: disputeData.amount.toFixed(2),
        ownerPayoutAmount: parseFloat(disputeData.ownerPayoutAmount || 0).toFixed(2),
        ownerName: disputeData.ownerName || "Unknown",
        ownerEmail: disputeData.ownerEmail || "Unknown",
      };

      const htmlContent = await this.templateManager.renderTemplate(
        "disputeLostAlertToAdmin",
        variables
      );

      const adminEmail = process.env.ADMIN_EMAIL || process.env.SES_FROM_EMAIL;

      return await this.emailClient.sendEmail(
        adminEmail,
        `ACTION REQUIRED: Dispute Lost - Owner Already Paid - Rental #${disputeData.rentalId}`,
        htmlContent
      );
    } catch (error) {
      logger.error("Failed to send dispute lost alert email", { error });
      return { success: false, error: error.message };
    }
  }

  /**
   * Format Stripe dispute reason codes to human-readable text
   * @param {string} reason - Stripe dispute reason code
   * @returns {string} Human-readable reason
   */
  formatDisputeReason(reason) {
    const reasonMap = {
      duplicate: "Duplicate charge",
      fraudulent: "Fraudulent transaction",
      subscription_canceled: "Subscription canceled",
      product_unacceptable: "Product unacceptable",
      product_not_received: "Product not received",
      unrecognized: "Unrecognized charge",
      credit_not_processed: "Credit not processed",
      general: "General dispute",
    };
    return reasonMap[reason] || reason || "Unknown reason";
  }
}

module.exports = PaymentEmailService;
