/**
 * Email Notification Service
 * 
 * High-level service for sending templated emails
 * Integrates: Templates + Preference Checking + Email Service
 */

import { emailService } from './email.service';
import {
  getRequestCreatedEmail,
  getApprovalRequestEmail,
  getMultiApproverRequestEmail,
  getApprovalConfirmationEmail,
  getRejectionNotificationEmail,
  getTATReminderEmail,
  getTATBreachedEmail,
  getWorkflowPausedEmail,
  getWorkflowResumedEmail,
  getParticipantAddedEmail,
  getSpectatorAddedEmail,
  getApproverSkippedEmail,
  getRequestClosedEmail,
  getDealerProposalSubmittedEmail,
  getDealerProposalRequiredEmail,
  getDealerCompletionRequiredEmail,
  getActivityCreatedEmail,
  getCompletionDocumentsSubmittedEmail,
  getEInvoiceGeneratedEmail,
  getCreditNoteSentEmail,
  getAdditionalDocumentAddedEmail,
  getViewDetailsLink,
  getTemplateTypeLabel,
  CompanyInfo,
  RequestCreatedData,
  ApprovalRequestData,
  MultiApproverRequestData,
  ApprovalConfirmationData,
  RejectionNotificationData,
  TATReminderData,
  TATBreachedData,
  WorkflowPausedData,
  WorkflowResumedData,
  ParticipantAddedData,
  SpectatorAddedData,
  ApproverSkippedData,
  RequestClosedData,
  DealerProposalSubmittedData,
  DealerProposalRequiredData,
  ActivityCreatedData,
  CompletionDocumentsSubmittedData,
  EInvoiceGeneratedData,
  CreditNoteSentData,
  AdditionalDocumentAddedData,
  ApprovalChainItem
} from '../emailtemplates';
import {
  shouldSendEmail,
  shouldSendEmailWithOverride,
  EmailNotificationType
} from '../emailtemplates/emailPreferences.helper';
import logger from '@utils/logger';
import dayjs from 'dayjs';

export class EmailNotificationService {
  private frontendUrl: string;

  constructor() {
    this.frontendUrl = process.env.FRONTEND_URL || 'http://localhost:3000';
  }

  /**
   * Helper: Format date for emails
   */
  private formatDate(date: Date | string): string {
    return dayjs(date).format('MMM DD, YYYY');
  }

  /**
   * Helper: Format time for emails
   */
  private formatTime(date: Date | string): string {
    return dayjs(date).format('hh:mm A');
  }

  /**
   * 1. Send Request Created Email
   */
  async sendRequestCreated(
    requestData: any,
    initiatorData: any,
    firstApproverData: any
  ): Promise<void> {
    try {
      // Check preferences
      const canSend = await shouldSendEmail(
        initiatorData.userId,
        EmailNotificationType.REQUEST_CREATED
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): Request Created for ${initiatorData.email}`);
        return;
      }

      const data: RequestCreatedData = {
        recipientName: initiatorData.displayName || initiatorData.email,
        requestId: requestData.requestNumber,
        requestTitle: requestData.title,
        initiatorName: initiatorData.displayName || initiatorData.email,
        firstApproverName: firstApproverData.displayName || firstApproverData.email,
        requestType: getTemplateTypeLabel(requestData.templateType || requestData.requestType),
        priority: requestData.priority || 'MEDIUM',
        requestDate: this.formatDate(requestData.createdAt),
        requestTime: this.formatTime(requestData.createdAt),
        totalApprovers: requestData.totalApprovers || 1,
        expectedTAT: requestData.tatHours || 24,
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name
      };

      const html = getRequestCreatedEmail(data);
      const subject = `${requestData.requestNumber} - ${requestData.title} - Request Created Successfully`;

      const result = await emailService.sendEmail({
        to: initiatorData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 Request Created Email Preview: ${result.previewUrl}`);
      }
    } catch (error) {
      logger.error('Failed to send Request Created email:', error);
      // Don't throw - email failure shouldn't block workflow
    }
  }

  /**
   * 2. Send Approval Request Email
   */
  async sendApprovalRequest(
    requestData: any,
    approverData: any,
    initiatorData: any,
    isMultiLevel: boolean,
    approvalChain?: any[],
    customMessage?: string
  ): Promise<void> {
    try {
      // Check preferences
      const canSend = await shouldSendEmail(
        approverData.userId,
        EmailNotificationType.APPROVAL_REQUEST
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): Approval Request for ${approverData.email}`);
        return;
      }

      if (isMultiLevel && approvalChain) {
        // Multi-level approval email
        const chainData: ApprovalChainItem[] = approvalChain.map((level: any) => ({
          name: level.approverName || level.approverEmail,
          status: level.status === 'APPROVED' ? 'approved'
            : level.levelNumber === approverData.levelNumber ? 'current'
              : level.levelNumber < approverData.levelNumber ? 'pending'
                : 'awaiting',
          date: level.approvedAt ? this.formatDate(level.approvedAt) : undefined,
          levelNumber: level.levelNumber
        }));

        const data: MultiApproverRequestData = {
          recipientName: approverData.displayName || approverData.email,
          requestId: requestData.requestNumber,
          requestTitle: requestData.title,
          approverName: approverData.displayName || approverData.email,
          initiatorName: initiatorData.displayName || initiatorData.email,
          requestType: getTemplateTypeLabel(requestData.templateType || requestData.requestType),
          requestDescription: requestData.description || '',
          priority: requestData.priority || 'MEDIUM',
          requestDate: this.formatDate(requestData.createdAt),
          requestTime: this.formatTime(requestData.createdAt),
          approverLevel: approverData.levelNumber,
          totalApprovers: approvalChain.length,
          approversList: chainData,
          viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
          companyName: CompanyInfo.name,
          customMessage
        };

        const html = getMultiApproverRequestEmail(data);
        const subject = `${requestData.requestNumber} - ${requestData.title} - Multi-Level Approval Request - Your Turn`;

        const result = await emailService.sendEmail({
          to: approverData.email,
          subject,
          html
        });

        if (result.previewUrl) {
          logger.info(`📧 Multi-Approver Request Email Preview: ${result.previewUrl}`);
        }
      } else {
        // Single approver email
        const data: ApprovalRequestData = {
          recipientName: approverData.displayName || approverData.email,
          requestId: requestData.requestNumber,
          requestTitle: requestData.title,
          approverName: approverData.displayName || approverData.email,
          initiatorName: initiatorData.displayName || initiatorData.email,
          requestType: getTemplateTypeLabel(requestData.templateType || requestData.requestType),
          requestDescription: requestData.description || '',
          priority: requestData.priority || 'MEDIUM',
          requestDate: this.formatDate(requestData.createdAt),
          requestTime: this.formatTime(requestData.createdAt),
          viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
          companyName: CompanyInfo.name,
          customMessage
        };

        const html = getApprovalRequestEmail(data);
        const subject = `${requestData.requestNumber} - ${requestData.title} - Approval Request - Action Required`;

        const result = await emailService.sendEmail({
          to: approverData.email,
          subject,
          html
        });

        if (result.previewUrl) {
          logger.info(`📧 Approval Request Email Preview: ${result.previewUrl}`);
        }
      }
    } catch (error) {
      logger.error('Failed to send Approval Request email:', error);
    }
  }

  /**
   * 3. Send Approval Confirmation Email
   */
  async sendApprovalConfirmation(
    requestData: any,
    approverData: any,
    initiatorData: any,
    isFinalApproval: boolean,
    nextApproverData?: any
  ): Promise<void> {
    try {
      const canSend = await shouldSendEmail(
        initiatorData.userId,
        EmailNotificationType.REQUEST_APPROVED
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): Approval Confirmation for ${initiatorData.email}`);
        return;
      }

      const data: ApprovalConfirmationData = {
        recipientName: initiatorData.displayName || initiatorData.email,
        requestId: requestData.requestNumber,
        initiatorName: initiatorData.displayName || initiatorData.email,
        approverName: approverData.displayName || approverData.email,
        approvalDate: this.formatDate(approverData.approvedAt || new Date()),
        approvalTime: this.formatTime(approverData.approvedAt || new Date()),
        requestType: getTemplateTypeLabel(requestData.templateType || requestData.requestType),
        approverComments: approverData.comments || undefined,
        isFinalApproval,
        nextApproverName: nextApproverData?.displayName || nextApproverData?.email,
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name
      };

      const html = getApprovalConfirmationEmail(data);
      const subject = `${requestData.requestNumber} - ${requestData.title} - Request Approved${isFinalApproval ? ' - All Approvals Complete' : ''}`;

      const result = await emailService.sendEmail({
        to: initiatorData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 Approval Confirmation Email Preview: ${result.previewUrl}`);
      }
    } catch (error) {
      logger.error('Failed to send Approval Confirmation email:', error);
    }
  }

  /**
   * 4. Send Rejection Notification Email (ESSENTIAL)
   */
  async sendRejectionNotification(
    requestData: any,
    approverData: any,
    initiatorData: any,
    rejectionReason: string
  ): Promise<void> {
    try {
      // 1. Skip if approver is the same as initiator
      if (approverData.userId && initiatorData.userId && approverData.userId === initiatorData.userId) {
        logger.info(`Email skipped: Approver ${approverData.userId} is the initiator, no need to notify self of rejection/return`);
        return;
      }

      const isReturnedForRevision = rejectionReason.includes('Revised Quotation Requested');

      // Use override for high-priority emails
      const canSend = await shouldSendEmailWithOverride(
        initiatorData.userId,
        EmailNotificationType.REQUEST_REJECTED
      );

      if (!canSend) {
        logger.info(`Email skipped (admin disabled): Rejection for ${initiatorData.email}`);
        return;
      }

      const data: RejectionNotificationData = {
        recipientName: initiatorData.displayName || initiatorData.email,
        requestId: requestData.requestNumber,
        initiatorName: initiatorData.displayName || initiatorData.email,
        approverName: approverData.displayName || approverData.email,
        rejectionDate: this.formatDate(approverData.rejectedAt || new Date()),
        rejectionTime: this.formatTime(approverData.rejectedAt || new Date()),
        requestType: getTemplateTypeLabel(requestData.templateType || requestData.requestType),
        rejectionReason,
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name,
        isReturnedForRevision
      };

      const html = getRejectionNotificationEmail(data);
      const subject = isReturnedForRevision 
        ? `${requestData.requestNumber} - ${requestData.title} - Request Returned for Revision`
        : `${requestData.requestNumber} - ${requestData.title} - Request Rejected`;

      const result = await emailService.sendEmail({
        to: initiatorData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 Rejection Notification Email Preview: ${result.previewUrl}`);
      }
    } catch (error) {
      logger.error('Failed to send Rejection Notification email:', error);
    }
  }

  /**
   * 5. Send TAT Reminder Email (Dynamic Threshold)
   */
  async sendTATReminder(
    requestData: any,
    approverData: any,
    tatInfo: {
      thresholdPercentage: number;
      timeRemaining: string;
      tatDeadline: Date | string;
      assignedDate: Date | string;
    }
  ): Promise<void> {
    try {
      const canSend = await shouldSendEmail(
        approverData.userId,
        EmailNotificationType.TAT_REMINDER
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): TAT Reminder for ${approverData.email}`);
        return;
      }

      // Determine urgency level based on threshold
      const urgencyLevel = tatInfo.thresholdPercentage >= 75 ? 'high'
        : tatInfo.thresholdPercentage >= 50 ? 'medium'
          : 'low';

      // Get initiator name - try from requestData first, then fetch if needed
      let initiatorName = requestData.initiatorName || requestData.initiator?.displayName || 'Initiator';
      if (initiatorName === 'Initiator' && requestData.initiatorId) {
        try {
          const { User } = await import('@models/index');
          const initiator = await User.findByPk(requestData.initiatorId);
          if (initiator) {
            const initiatorJson = initiator.toJSON();
            initiatorName = initiatorJson.displayName || initiatorJson.email || 'Initiator';
          }
        } catch (error) {
          logger.warn(`Failed to fetch initiator for TAT reminder: ${error}`);
        }
      }

      const data: TATReminderData = {
        recipientName: approverData.displayName || approverData.email,
        requestId: requestData.requestNumber,
        requestTitle: requestData.title,
        approverName: approverData.displayName || approverData.email,
        initiatorName: initiatorName,
        assignedDate: this.formatDate(tatInfo.assignedDate),
        tatDeadline: this.formatDate(tatInfo.tatDeadline) + ' ' + this.formatTime(tatInfo.tatDeadline),
        timeRemaining: tatInfo.timeRemaining,
        thresholdPercentage: tatInfo.thresholdPercentage,
        urgencyLevel: urgencyLevel as any,
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name
      };

      const html = getTATReminderEmail(data);
      const subject = `${requestData.requestNumber} - ${requestData.title} - TAT Reminder - ${tatInfo.thresholdPercentage}% Elapsed`;

      const result = await emailService.sendEmail({
        to: approverData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 TAT Reminder (${tatInfo.thresholdPercentage}%) Email Preview: ${result.previewUrl}`);
      }
    } catch (error) {
      logger.error('Failed to send TAT Reminder email:', error);
    }
  }

  /**
   * 6. Send TAT Breached Email (ESSENTIAL)
   */
  async sendTATBreached(
    requestData: any,
    approverData: any,
    tatInfo: {
      timeOverdue: string;
      tatDeadline: Date | string;
      assignedDate: Date | string;
    }
  ): Promise<void> {
    try {
      // Use override for high-priority emails
      const canSend = await shouldSendEmailWithOverride(
        approverData.userId,
        EmailNotificationType.TAT_BREACHED
      );

      if (!canSend) {
        logger.info(`Email skipped (admin disabled): TAT Breach for ${approverData.email}`);
        return;
      }

      // Get initiator name - try from requestData first, then fetch if needed
      let initiatorName = requestData.initiatorName || requestData.initiator?.displayName || 'Initiator';
      if (initiatorName === 'Initiator' && requestData.initiatorId) {
        try {
          const { User } = await import('@models/index');
          const initiator = await User.findByPk(requestData.initiatorId);
          if (initiator) {
            const initiatorJson = initiator.toJSON();
            initiatorName = initiatorJson.displayName || initiatorJson.email || 'Initiator';
          }
        } catch (error) {
          logger.warn(`Failed to fetch initiator for TAT breach: ${error}`);
        }
      }

      const data: TATBreachedData = {
        recipientName: approverData.displayName || approverData.email,
        requestId: requestData.requestNumber,
        requestTitle: requestData.title,
        approverName: approverData.displayName || approverData.email,
        initiatorName: initiatorName,
        priority: requestData.priority || 'MEDIUM',
        assignedDate: this.formatDate(tatInfo.assignedDate),
        tatDeadline: this.formatDate(tatInfo.tatDeadline) + ' ' + this.formatTime(tatInfo.tatDeadline),
        timeOverdue: tatInfo.timeOverdue,
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name
      };

      const html = getTATBreachedEmail(data);
      const subject = `${requestData.requestNumber} - ${requestData.title} - TAT BREACHED - Immediate Action Required`;

      const result = await emailService.sendEmail({
        to: approverData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 TAT Breached Email Preview: ${result.previewUrl}`);
      }
    } catch (error) {
      logger.error('Failed to send TAT Breached email:', error);
    }
  }

  /**
   * 7. Send Workflow Resumed Email
   */
  async sendWorkflowResumed(
    requestData: any,
    approverData: any,
    initiatorData: any,
    resumedByData: any,
    pauseDuration: string
  ): Promise<void> {
    try {
      // Validate approver data has email
      if (!approverData || !approverData.email) {
        logger.warn(`[Email] Cannot send Workflow Resumed email: approver email missing`, {
          approverData: approverData ? { userId: approverData.userId, displayName: approverData.displayName } : null,
          requestNumber: requestData.requestNumber
        });
        return;
      }

      const canSend = await shouldSendEmail(
        approverData.userId,
        EmailNotificationType.WORKFLOW_RESUMED
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): Workflow Resumed for ${approverData.email}`);
        return;
      }

      const isAutoResumed = !resumedByData || resumedByData.userId === 'system';
      const resumedByText = isAutoResumed
        ? 'automatically'
        : `by ${resumedByData.displayName || resumedByData.email}`;

      const data: WorkflowResumedData = {
        recipientName: approverData.displayName || approverData.email,
        requestId: requestData.requestNumber,
        requestTitle: requestData.title,
        resumedByText,
        resumedDate: this.formatDate(new Date()),
        resumedTime: this.formatTime(new Date()),
        pausedDuration: pauseDuration,
        currentApprover: approverData.displayName || approverData.email,
        newTATDeadline: requestData.tatDeadline
          ? this.formatDate(requestData.tatDeadline) + ' ' + this.formatTime(requestData.tatDeadline)
          : 'To be determined',
        isApprover: true,
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name
      };

      const html = getWorkflowResumedEmail(data);
      const subject = `${requestData.requestNumber} - ${requestData.title} - Workflow Resumed - Action Required`;

      const result = await emailService.sendEmail({
        to: approverData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 Workflow Resumed Email Preview: ${result.previewUrl}`);
      }
    } catch (error) {
      logger.error('Failed to send Workflow Resumed email:', error);
    }
  }

  /**
   * Send Workflow Resumed Email to Initiator
   */
  async sendWorkflowResumedToInitiator(
    requestData: any,
    initiatorData: any,
    approverData: any,
    resumedByData: any,
    pauseDuration: string
  ): Promise<void> {
    try {
      // Validate initiator data has email
      if (!initiatorData || !initiatorData.email) {
        logger.warn(`[Email] Cannot send Workflow Resumed email to initiator: email missing`, {
          initiatorData: initiatorData ? { userId: initiatorData.userId, displayName: initiatorData.displayName } : null,
          requestNumber: requestData.requestNumber
        });
        return;
      }

      const canSend = await shouldSendEmail(
        initiatorData.userId,
        EmailNotificationType.WORKFLOW_RESUMED
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): Workflow Resumed for initiator ${initiatorData.email}`);
        return;
      }

      const isAutoResumed = !resumedByData || resumedByData.userId === 'system' || !resumedByData.userId;
      const resumedByText = isAutoResumed
        ? 'automatically'
        : `by ${resumedByData.displayName || resumedByData.email || resumedByData.name || 'User'}`;

      const data: WorkflowResumedData = {
        recipientName: initiatorData.displayName || initiatorData.email,
        requestId: requestData.requestNumber,
        requestTitle: requestData.title,
        resumedByText,
        resumedDate: this.formatDate(new Date()),
        resumedTime: this.formatTime(new Date()),
        pausedDuration: pauseDuration,
        currentApprover: approverData?.displayName || approverData?.email || 'Current Approver',
        newTATDeadline: requestData.tatDeadline
          ? this.formatDate(requestData.tatDeadline) + ' ' + this.formatTime(requestData.tatDeadline)
          : 'To be determined',
        isApprover: false, // This is for initiator
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name
      };

      const html = getWorkflowResumedEmail(data);
      const subject = `${requestData.requestNumber} - ${requestData.title} - Workflow Resumed`;

      const result = await emailService.sendEmail({
        to: initiatorData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 Workflow Resumed Email Preview (Initiator): ${result.previewUrl}`);
      }
    } catch (error) {
      logger.error('Failed to send Workflow Resumed email to initiator:', error);
    }
  }

  /**
   * 8. Send Request Closed Email
   */
  async sendRequestClosed(
    requestData: any,
    recipientData: any,
    closureData: {
      conclusionRemark?: string;
      workNotesCount: number;
      documentsCount: number;
    }
  ): Promise<void> {
    try {
      const canSend = await shouldSendEmail(
        recipientData.userId,
        EmailNotificationType.REQUEST_CLOSED
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): Request Closed for ${recipientData.email}`);
        return;
      }

      const createdDate = requestData.createdAt ? dayjs(requestData.createdAt) : dayjs();
      const closedDate = requestData.closedAt ? dayjs(requestData.closedAt) : dayjs();
      const duration = closedDate.diff(createdDate, 'day');
      const totalDuration = `${duration} day${duration !== 1 ? 's' : ''}`;

      // Get initiator name - try from requestData first, then fetch if needed
      let initiatorName = requestData.initiatorName || requestData.initiator?.displayName || 'Initiator';
      if (initiatorName === 'Initiator' && requestData.initiatorId) {
        try {
          const { User } = await import('@models/index');
          const initiator = await User.findByPk(requestData.initiatorId);
          if (initiator) {
            const initiatorJson = initiator.toJSON();
            initiatorName = initiatorJson.displayName || initiatorJson.email || 'Initiator';
          }
        } catch (error) {
          logger.warn(`Failed to fetch initiator for closed request: ${error}`);
        }
      }

      const data: RequestClosedData = {
        recipientName: recipientData.displayName || recipientData.email,
        requestId: requestData.requestNumber,
        requestTitle: requestData.title,
        initiatorName: initiatorName,
        createdDate: this.formatDate(requestData.createdAt),
        closedDate: this.formatDate(requestData.closedAt || new Date()),
        closedTime: this.formatTime(requestData.closedAt || new Date()),
        totalDuration,
        conclusionRemark: closureData.conclusionRemark,
        totalApprovers: requestData.totalApprovers || 0,
        totalApprovals: requestData.totalApprovals || 0,
        workNotesCount: closureData.workNotesCount,
        documentsCount: closureData.documentsCount,
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name
      };

      const html = getRequestClosedEmail(data);
      const subject = `${requestData.requestNumber} - ${requestData.title} - Request Closed`;

      const result = await emailService.sendEmail({
        to: recipientData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 Request Closed Email Preview: ${result.previewUrl}`);
      }
    } catch (error) {
      logger.error('Failed to send Request Closed email:', error);
    }
  }

  /**
   * Send emails to multiple recipients (for Request Closed)
   */
  async sendRequestClosedToAll(
    requestData: any,
    participants: any[],
    closureData: any
  ): Promise<void> {
    logger.info(`📧 Sending Request Closed emails to ${participants.length} participants`);

    for (const participant of participants) {
      await this.sendRequestClosed(requestData, participant, closureData);
      // Small delay to avoid rate limiting
      await new Promise(resolve => setTimeout(resolve, 100));
    }
  }

  /**
   * 9. Send Approver Skipped Email
   */
  async sendApproverSkipped(
    requestData: any,
    skippedApproverData: any,
    skippedByData: any,
    nextApproverData: any,
    skipReason: string
  ): Promise<void> {
    try {
      const canSend = await shouldSendEmail(
        skippedApproverData.userId,
        EmailNotificationType.APPROVER_SKIPPED
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): Approver Skipped for ${skippedApproverData.email}`);
        return;
      }

      const data: ApproverSkippedData = {
        recipientName: skippedApproverData.displayName || skippedApproverData.email,
        requestId: requestData.requestNumber,
        requestTitle: requestData.title,
        skippedApproverName: skippedApproverData.displayName || skippedApproverData.email,
        skippedByName: skippedByData.displayName || skippedByData.email,
        skippedDate: this.formatDate(new Date()),
        skippedTime: this.formatTime(new Date()),
        nextApproverName: nextApproverData?.displayName || nextApproverData?.email || 'Next Approver',
        skipReason: skipReason || 'Not provided',
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name
      };

      const html = getApproverSkippedEmail(data);
      const subject = `${requestData.requestNumber} - ${requestData.title} - Approver Skipped`;

      const result = await emailService.sendEmail({
        to: skippedApproverData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 Approver Skipped Email Preview: ${result.previewUrl}`);
      }
    } catch (error) {
      logger.error('Failed to send Approver Skipped email:', error);
    }
  }

  /**
   * 10. Send Workflow Paused Email
   */
  async sendWorkflowPaused(
    requestData: any,
    recipientData: any,
    pausedByData: any,
    pauseReason: string,
    resumeDate: Date | string
  ): Promise<void> {
    try {
      // Validate recipient data has email
      if (!recipientData || !recipientData.email) {
        logger.warn(`[Email] Cannot send Workflow Paused email: recipient email missing`, {
          recipientData: recipientData ? { userId: recipientData.userId, displayName: recipientData.displayName } : null,
          requestNumber: requestData.requestNumber
        });
        return;
      }

      const canSend = await shouldSendEmail(
        recipientData.userId,
        EmailNotificationType.WORKFLOW_PAUSED
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): Workflow Paused for ${recipientData.email}`);
        return;
      }

      const data: WorkflowPausedData = {
        recipientName: recipientData.displayName || recipientData.email,
        requestId: requestData.requestNumber,
        requestTitle: requestData.title,
        pausedByName: pausedByData?.displayName || pausedByData?.email || 'System',
        pausedDate: this.formatDate(new Date()),
        pausedTime: this.formatTime(new Date()),
        resumeDate: this.formatDate(resumeDate),
        pauseReason: pauseReason || 'Not provided',
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name
      };

      const html = getWorkflowPausedEmail(data);
      const subject = `${requestData.requestNumber} - ${requestData.title} - Workflow Paused`;

      const result = await emailService.sendEmail({
        to: recipientData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 Workflow Paused Email Preview: ${result.previewUrl}`);
      }
    } catch (error) {
      logger.error('Failed to send Workflow Paused email:', error);
    }
  }

  /**
   * 11. Send Spectator Added Email
   */
  async sendSpectatorAdded(
    requestData: any,
    spectatorData: any,
    addedByData?: any,
    initiatorData?: any
  ): Promise<void> {
    try {
      const canSend = await shouldSendEmail(
        spectatorData.userId,
        EmailNotificationType.SPECTATOR_ADDED
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): Spectator Added for ${spectatorData.email}`);
        return;
      }

      // Get initiator name
      let initiatorName = 'Initiator';
      if (initiatorData) {
        initiatorName = initiatorData.displayName || initiatorData.email || 'Initiator';
      } else if (requestData.initiatorId) {
        try {
          const { User } = await import('@models/index');
          const initiator = await User.findByPk(requestData.initiatorId);
          if (initiator) {
            const initiatorJson = initiator.toJSON();
            initiatorName = initiatorJson.displayName || initiatorJson.email || 'Initiator';
          }
        } catch (error) {
          logger.warn(`Failed to fetch initiator for spectator added email: ${error}`);
        }
      }

      // Get added by name
      let addedByName: string | undefined;
      if (addedByData) {
        addedByName = addedByData.displayName || addedByData.email;
      }

      // Get participant to check when they were added
      const { Participant } = await import('@models/index');
      const participant = await Participant.findOne({
        where: {
          requestId: requestData.requestId,
          userId: spectatorData.userId
        }
      });

      const addedDate = participant ? this.formatDate((participant as any).addedAt || new Date()) : this.formatDate(new Date());
      const addedTime = participant ? this.formatTime((participant as any).addedAt || new Date()) : this.formatTime(new Date());

      const data: SpectatorAddedData = {
        recipientName: spectatorData.displayName || spectatorData.email,
        spectatorName: spectatorData.displayName || spectatorData.email,
        addedByName: addedByName,
        initiatorName: initiatorName,
        requestId: requestData.requestNumber,
        requestTitle: requestData.title,
        requestType: getTemplateTypeLabel(requestData.templateType || requestData.workflowType),
        currentStatus: requestData.status || undefined,
        addedDate: addedDate,
        addedTime: addedTime,
        requestDescription: requestData.description || undefined,
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name
      };

      const html = getSpectatorAddedEmail(data);
      const subject = `[${requestData.requestNumber}] Added as Spectator`;

      const result = await emailService.sendEmail({
        to: spectatorData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 Spectator Added Email Preview: ${result.previewUrl}`);
      }
      logger.info(`✅ Spectator Added email sent to ${spectatorData.email} for request ${requestData.requestNumber}`);
    } catch (error) {
      logger.error(`Failed to send Spectator Added email:`, error);
      throw error;
    }
  }

  /**
   * 11a. Send Participant Added Email (for Additional Approvers)
   */
  async sendParticipantAdded(
    requestData: any,
    participantData: any,
    addedByData?: any,
    initiatorData?: any
  ): Promise<void> {
    try {
      const canSend = await shouldSendEmail(
        participantData.userId,
        EmailNotificationType.PARTICIPANT_ADDED
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): Participant Added for ${participantData.email}`);
        return;
      }

      // Get initiator name
      let initiatorName = 'Initiator';
      if (initiatorData) {
        initiatorName = initiatorData.displayName || initiatorData.email || 'Initiator';
      } else if (requestData.initiatorId) {
        try {
          const { User } = await import('@models/index');
          const initiator = await User.findByPk(requestData.initiatorId);
          if (initiator) {
            const initiatorJson = initiator.toJSON();
            initiatorName = initiatorJson.displayName || initiatorJson.email || 'Initiator';
          }
        } catch (error) {
          logger.warn(`Failed to fetch initiator for participant added email: ${error}`);
        }
      }

      // Get added by name
      let addedByName: string | undefined;
      if (addedByData) {
        addedByName = addedByData.displayName || addedByData.email;
      }

      // Get participant to check when they were added
      const { Participant } = await import('@models/index');
      const participant = await Participant.findOne({
        where: {
          requestId: requestData.requestId || requestData.workflowRequestId,
          userId: participantData.userId
        }
      });

      const addedDate = participant ? this.formatDate((participant as any).addedAt || new Date()) : this.formatDate(new Date());
      const addedTime = participant ? this.formatTime((participant as any).addedAt || new Date()) : this.formatTime(new Date());

      const data: ParticipantAddedData = {
        recipientName: participantData.displayName || participantData.email,
        participantName: participantData.displayName || participantData.email,
        participantRole: 'Approver',
        addedByName: addedByName || 'Admin',
        initiatorName: initiatorName,
        requestId: requestData.requestNumber,
        requestTitle: requestData.title,
        requestType: getTemplateTypeLabel(requestData.templateType || requestData.workflowType),
        currentStatus: requestData.status || 'PENDING',
        addedDate: addedDate,
        addedTime: addedTime,
        requestDescription: requestData.description || '',
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name
      };

      const html = getParticipantAddedEmail(data);
      const subject = `[${requestData.requestNumber}] Added as Additional Approver`;

      const result = await emailService.sendEmail({
        to: participantData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 Participant Added Email Preview: ${result.previewUrl}`);
      }
      logger.info(`✅ Participant Added email sent to ${participantData.email} for request ${requestData.requestNumber}`);
    } catch (error) {
      logger.error(`Failed to send Participant Added email:`, error);
    }
  }

  /**
   * 12. Send Dealer Proposal Required Email
   */
  async sendDealerProposalRequired(
    requestData: any,
    dealerData: any,
    initiatorData: any,
    claimData?: any,
    customMessage?: string
  ): Promise<void> {
    try {
      const canSend = await shouldSendEmail(
        dealerData.userId,
        EmailNotificationType.APPROVAL_REQUEST // Use approval_request type for preferences
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): Dealer Proposal Required for ${dealerData.email}`);
        return;
      }

      // Calculate due date from TAT if available
      let dueDate: string | undefined;
      if (claimData?.tatHours) {
        const dueDateObj = dayjs().add(claimData.tatHours, 'hour');
        dueDate = dueDateObj.format('MMMM D, YYYY');
      }

      const data: DealerProposalRequiredData = {
        recipientName: dealerData.displayName || dealerData.email,
        requestId: requestData.requestNumber,
        requestTitle: requestData.title,
        dealerName: dealerData.displayName || dealerData.email || claimData?.dealerName || 'Dealer',
        initiatorName: initiatorData.displayName || initiatorData.email,
        activityName: claimData?.activityName || requestData.title,
        activityType: claimData?.activityType || 'N/A',
        activityDate: claimData?.activityDate ? this.formatDate(claimData.activityDate) : undefined,
        location: claimData?.location,
        estimatedBudget: claimData?.estimatedBudget,
        requestDate: this.formatDate(requestData.createdAt),
        requestTime: this.formatTime(requestData.createdAt),
        requestDescription: requestData.description || '',
        priority: requestData.priority || 'MEDIUM',
        tatHours: claimData?.tatHours,
        dueDate: dueDate,
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name,
        customMessage
      };

      const html = getDealerProposalRequiredEmail(data);
      const subject = `[${requestData.requestNumber}] Proposal Required - ${data.activityName}`;

      const result = await emailService.sendEmail({
        to: dealerData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 Dealer Proposal Required Email Preview: ${result.previewUrl}`);
      }
      logger.info(`✅ Dealer Proposal Required email sent to ${dealerData.email} for request ${requestData.requestNumber}`);
    } catch (error) {
      logger.error(`Failed to send Dealer Proposal Required email:`, error);
      throw error;
    }
  }

  /**
   * 12a. Send Re-Quotation Required Email
   * (Uses Proposal Required template with custom subject and rejection reason)
   */
  async sendReQuotationRequired(
    requestData: any,
    dealerData: any,
    initiatorData: any,
    claimData: any,
    rejectionReason: string
  ): Promise<void> {
    try {
      const canSend = await shouldSendEmail(
        dealerData.userId,
        EmailNotificationType.RE_QUOTATION
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): Re-Quotation Required for ${dealerData.email}`);
        return;
      }

      // Calculate due date from TAT if available
      let dueDate: string | undefined;
      if (claimData?.tatHours) {
        const dueDateObj = dayjs().add(claimData.tatHours, 'hour');
        dueDate = dueDateObj.format('MMMM D, YYYY');
      }

      const data: DealerProposalRequiredData = {
        recipientName: dealerData.displayName || dealerData.email,
        requestId: requestData.requestNumber,
        requestTitle: requestData.title,
        dealerName: dealerData.displayName || dealerData.email || claimData?.dealerName || 'Dealer',
        initiatorName: initiatorData.displayName || initiatorData.email,
        activityName: claimData?.activityName || requestData.title,
        activityType: claimData?.activityType || 'N/A',
        activityDate: claimData?.activityDate ? this.formatDate(claimData.activityDate) : undefined,
        location: claimData?.location,
        estimatedBudget: claimData?.estimatedBudget,
        requestDate: this.formatDate(requestData.createdAt),
        requestTime: this.formatTime(requestData.createdAt),
        requestDescription: requestData.description || '',
        priority: requestData.priority || 'MEDIUM',
        tatHours: claimData?.tatHours,
        dueDate: dueDate,
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name,
        customMessage: rejectionReason
      };

      const html = getDealerProposalRequiredEmail(data);
      const subject = `[${requestData.requestNumber}] Revised Quotation Requested - ${data.activityName}`;

      const result = await emailService.sendEmail({
        to: dealerData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 Re-Quotation Required Email Preview: ${result.previewUrl}`);
      }
      logger.info(`✅ Re-Quotation Required email sent to ${dealerData.email} for request ${requestData.requestNumber}`);
    } catch (error) {
      logger.error(`Failed to send Re-Quotation Required email:`, error);
      throw error;
    }
  }

  /**
   * 12b. Send Dealer Completion Documents Required Email
   */
  async sendDealerCompletionRequired(
    requestData: any,
    dealerData: any,
    initiatorData: any,
    claimData?: any,
    customMessage?: string
  ): Promise<void> {
    try {
      const canSend = await shouldSendEmail(
        dealerData.userId,
        EmailNotificationType.APPROVAL_REQUEST // Use approval_request type for preferences
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): Dealer Completion Required for ${dealerData.email}`);
        return;
      }

      // Calculate due date from TAT if available
      let dueDate: string | undefined;
      if (claimData?.tatHours) {
        const dueDateObj = dayjs().add(claimData.tatHours, 'hour');
        dueDate = dueDateObj.format('MMMM D, YYYY');
      }

      const data: DealerProposalRequiredData = {
        recipientName: dealerData.displayName || dealerData.email,
        requestId: requestData.requestNumber,
        requestTitle: requestData.title,
        dealerName: dealerData.displayName || dealerData.email || claimData?.dealerName || 'Dealer',
        initiatorName: initiatorData.displayName || initiatorData.email,
        activityName: claimData?.activityName || requestData.title,
        activityType: claimData?.activityType || 'N/A',
        activityDate: claimData?.activityDate ? this.formatDate(claimData.activityDate) : undefined,
        location: claimData?.location,
        estimatedBudget: claimData?.estimatedBudget,
        requestDate: this.formatDate(requestData.createdAt),
        requestTime: this.formatTime(requestData.createdAt),
        requestDescription: requestData.description || '',
        priority: requestData.priority || 'MEDIUM',
        tatHours: claimData?.tatHours,
        dueDate: dueDate,
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name,
        customMessage
      };

      const html = getDealerCompletionRequiredEmail(data);
      const subject = `[${requestData.requestNumber}] Completion Documents Required - ${data.activityName}`;

      const result = await emailService.sendEmail({
        to: dealerData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 Dealer Completion Required Email Preview: ${result.previewUrl}`);
      }
      logger.info(`✅ Dealer Completion Required email sent to ${dealerData.email} for request ${requestData.requestNumber}`);
    } catch (error) {
      logger.error(`Failed to send Dealer Completion Required email:`, error);
      throw error;
    }
  }

  /**
   * 13. Send Dealer Proposal Submitted Email
   */
  async sendDealerProposalSubmitted(
    requestData: any,
    dealerData: any,
    recipientData: any,
    proposalData: any,
    nextApproverData?: any
  ): Promise<void> {
    try {
      const canSend = await shouldSendEmail(
        recipientData.userId,
        EmailNotificationType.DEALER_PROPOSAL_SUBMITTED
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): Dealer Proposal Submitted for ${recipientData.email}`);
        return;
      }

      // Format cost breakdown summary if available
      let costBreakupSummary: string | undefined;
      if (proposalData.costBreakup && Array.isArray(proposalData.costBreakup) && proposalData.costBreakup.length > 0) {
        costBreakupSummary = '<table style="width: 100%; border-collapse: collapse;"><thead><tr style="background-color: #f8f9fa;"><th style="padding: 10px; text-align: left; border-bottom: 2px solid #e9ecef;">Description</th><th style="padding: 10px; text-align: right; border-bottom: 2px solid #e9ecef;">Amount</th></tr></thead><tbody>';
        proposalData.costBreakup.forEach((item: any) => {
          costBreakupSummary += `<tr><td style="padding: 8px; border-bottom: 1px solid #f0f0f0;">${item.description || ''}</td><td style="padding: 8px; text-align: right; border-bottom: 1px solid #f0f0f0;">₹${(item.amount || 0).toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</td></tr>`;
        });
        costBreakupSummary += '</tbody></table>';
      }

      // Check if next approver is the recipient (initiator reviewing their own request)
      const isNextApproverInitiator = proposalData.nextApproverIsInitiator ||
        (nextApproverData && nextApproverData.userId === recipientData.userId);

      const data: DealerProposalSubmittedData = {
        recipientName: recipientData.displayName || recipientData.email,
        requestId: requestData.requestNumber,
        requestTitle: requestData.title,
        dealerName: dealerData.displayName || dealerData.email || dealerData.name,
        activityName: requestData.activityName || requestData.title,
        activityType: requestData.activityType || 'N/A',
        proposalBudget: proposalData.totalEstimatedBudget || proposalData.proposalBudget || 0,
        expectedCompletionDate: proposalData.expectedCompletionDate || 'Not specified',
        dealerComments: proposalData.dealerComments,
        costBreakupSummary: costBreakupSummary,
        submittedDate: this.formatDate(proposalData.submittedAt || new Date()),
        submittedTime: this.formatTime(proposalData.submittedAt || new Date()),
        nextApproverName: isNextApproverInitiator
          ? undefined // Don't show next approver name if it's the recipient themselves
          : (nextApproverData?.displayName || nextApproverData?.email || (proposalData.nextApproverIsAdditional ? 'Additional Approver' : undefined)),
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name
      };

      const html = getDealerProposalSubmittedEmail(data);
      const subject = `[${requestData.requestNumber}] Proposal Submitted - ${data.activityName}`;

      const result = await emailService.sendEmail({
        to: recipientData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 Dealer Proposal Submitted Email Preview: ${result.previewUrl}`);
      }
      logger.info(`✅ Dealer Proposal Submitted email sent to ${recipientData.email} for request ${requestData.requestNumber}`);
    } catch (error) {
      logger.error(`Failed to send Dealer Proposal Submitted email:`, error);
      throw error;
    }
  }

  /**
   * 14. Send Activity Created Email
   */
  async sendActivityCreated(
    requestData: any,
    recipientData: any,
    activityData: any
  ): Promise<void> {
    try {
      const canSend = await shouldSendEmail(
        recipientData.userId,
        EmailNotificationType.ACTIVITY_CREATED
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): Activity Created for ${recipientData.email}`);
        return;
      }

      const data: ActivityCreatedData = {
        recipientName: recipientData.displayName || recipientData.email,
        requestId: requestData.requestNumber,
        requestTitle: requestData.title,
        activityName: activityData.activityName || requestData.title,
        activityType: activityData.activityType || 'N/A',
        activityDate: activityData.activityDate ? this.formatDate(activityData.activityDate) : undefined,
        location: activityData.location || 'Not specified',
        dealerName: activityData.dealerName || 'Dealer',
        dealerCode: activityData.dealerCode,
        initiatorName: activityData.initiatorName || 'Initiator',
        departmentLeadName: activityData.departmentLeadName,
        ioNumber: activityData.ioNumber,
        createdDate: this.formatDate(new Date()),
        createdTime: this.formatTime(new Date()),
        nextSteps: activityData.nextSteps || 'IO confirmation to be made. Dealer will proceed with activity execution.',
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name
      };

      const html = getActivityCreatedEmail(data);
      const subject = `[${requestData.requestNumber}] Activity Created - ${data.activityName}`;

      const result = await emailService.sendEmail({
        to: recipientData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 Activity Created Email Preview: ${result.previewUrl}`);
      }
      logger.info(`✅ Activity Created email sent to ${recipientData.email} for request ${requestData.requestNumber}`);
    } catch (error) {
      logger.error(`Failed to send Activity Created email:`, error);
      throw error;
    }
  }

  /**
   * 15. Send Completion Documents Submitted Email
   */
  async sendCompletionDocumentsSubmitted(
    requestData: any,
    dealerData: any,
    recipientData: any,
    completionData: any,
    nextApproverData?: any
  ): Promise<void> {
    try {
      const canSend = await shouldSendEmail(
        recipientData.userId,
        EmailNotificationType.COMPLETION_DOCUMENTS_SUBMITTED
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): Completion Documents Submitted for ${recipientData.email}`);
        return;
      }

      // Format expense breakdown summary if available
      let expenseBreakdown: string | undefined;
      if (completionData.closedExpenses && Array.isArray(completionData.closedExpenses) && completionData.closedExpenses.length > 0) {
        expenseBreakdown = '<table style="width: 100%; border-collapse: collapse;"><thead><tr style="background-color: #f8f9fa;"><th style="padding: 10px; text-align: left; border-bottom: 2px solid #e9ecef;">Description</th><th style="padding: 10px; text-align: right; border-bottom: 2px solid #e9ecef;">Amount</th></tr></thead><tbody>';
        completionData.closedExpenses.forEach((item: any) => {
          expenseBreakdown += `<tr><td style="padding: 8px; border-bottom: 1px solid #f0f0f0;">${item.description || ''}</td><td style="padding: 8px; text-align: right; border-bottom: 1px solid #f0f0f0;">₹${(item.amount || 0).toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</td></tr>`;
        });
        expenseBreakdown += '</tbody></table>';
      }

      // Check if next approver is the recipient (initiator reviewing their own request)
      const isNextApproverInitiator = completionData.nextApproverIsInitiator ||
        (nextApproverData && nextApproverData.userId === recipientData.userId);

      const data: CompletionDocumentsSubmittedData = {
        recipientName: recipientData.displayName || recipientData.email,
        requestId: requestData.requestNumber,
        requestTitle: requestData.title,
        dealerName: dealerData.displayName || dealerData.email || dealerData.name,
        activityName: requestData.activityName || requestData.title,
        activityCompletionDate: completionData.activityCompletionDate ? this.formatDate(completionData.activityCompletionDate) : 'Not specified',
        numberOfParticipants: completionData.numberOfParticipants,
        totalClosedExpenses: completionData.totalClosedExpenses || 0,
        expenseBreakdown: expenseBreakdown,
        documentsCount: completionData.documentsCount,
        submittedDate: this.formatDate(completionData.submittedAt || new Date()),
        submittedTime: this.formatTime(completionData.submittedAt || new Date()),
        nextApproverName: isNextApproverInitiator
          ? undefined // Don't show next approver name if it's the recipient themselves
          : (nextApproverData?.displayName || nextApproverData?.email || (completionData.nextApproverIsAdditional ? 'Additional Approver' : undefined)),
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name
      };

      const html = getCompletionDocumentsSubmittedEmail(data);
      const subject = `[${requestData.requestNumber}] Completion Documents Submitted - ${data.activityName}`;

      const result = await emailService.sendEmail({
        to: recipientData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 Completion Documents Submitted Email Preview: ${result.previewUrl}`);
      }
      logger.info(`✅ Completion Documents Submitted email sent to ${recipientData.email} for request ${requestData.requestNumber}`);
    } catch (error) {
      logger.error(`Failed to send Completion Documents Submitted email:`, error);
      throw error;
    }
  }

  /**
   * 16. Send E-Invoice Generated Email
   */
  async sendEInvoiceGenerated(
    requestData: any,
    recipientData: any,
    invoiceData: any
  ): Promise<void> {
    try {
      const canSend = await shouldSendEmail(
        recipientData.userId,
        EmailNotificationType.EINVOICE_GENERATED
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): E-Invoice Generated for ${recipientData.email}`);
        return;
      }

      const data: EInvoiceGeneratedData = {
        recipientName: recipientData.displayName || recipientData.email,
        requestId: requestData.requestNumber,
        requestTitle: requestData.title,
        invoiceNumber: invoiceData.invoiceNumber || invoiceData.eInvoiceNumber || 'N/A',
        invoiceDate: invoiceData.invoiceDate ? this.formatDate(invoiceData.invoiceDate) : this.formatDate(new Date()),
        dmsNumber: invoiceData.dmsNumber,
        invoiceAmount: invoiceData.amount || invoiceData.invoiceAmount || 0,
        dealerName: invoiceData.dealerName || requestData.dealerName || 'Dealer',
        dealerCode: invoiceData.dealerCode || requestData.dealerCode,
        activityName: requestData.activityName || requestData.title,
        ioNumber: invoiceData.ioNumber || requestData.ioNumber,
        generatedDate: this.formatDate(invoiceData.generatedAt || new Date()),
        generatedTime: this.formatTime(invoiceData.generatedAt || new Date()),
        downloadLink: invoiceData.downloadLink,
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name
      };

      const html = getEInvoiceGeneratedEmail(data);
      const subject = `[${requestData.requestNumber}] E-Invoice Generated - ${data.invoiceNumber}`;

      const result = await emailService.sendEmail({
        to: recipientData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 E-Invoice Generated Email Preview: ${result.previewUrl}`);
      }
      logger.info(`✅ E-Invoice Generated email sent to ${recipientData.email} for request ${requestData.requestNumber}`);
    } catch (error) {
      logger.error(`Failed to send E-Invoice Generated email:`, error);
      throw error;
    }
  }

  /**
   * 17. Send Credit Note Sent Email
   */
  async sendCreditNoteSent(
    requestData: any,
    recipientData: any,
    creditNoteData: any
  ): Promise<void> {
    try {
      const canSend = await shouldSendEmail(
        recipientData.userId,
        EmailNotificationType.CREDIT_NOTE_SENT
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): Credit Note Sent for ${recipientData.email}`);
        return;
      }

      const data: CreditNoteSentData = {
        recipientName: recipientData.displayName || recipientData.email,
        requestId: requestData.requestNumber,
        requestTitle: requestData.title,
        requestNumber: requestData.requestNumber,
        creditNoteNumber: creditNoteData.creditNoteNumber || 'N/A',
        creditNoteDate: creditNoteData.creditNoteDate ? this.formatDate(creditNoteData.creditNoteDate) : this.formatDate(new Date()),
        creditNoteAmount: creditNoteData.creditNoteAmount || 0,
        dealerName: creditNoteData.dealerName || requestData.dealerName || 'Dealer',
        dealerCode: creditNoteData.dealerCode || requestData.dealerCode,
        dealerEmail: creditNoteData.dealerEmail || requestData.dealerEmail || '',
        activityName: requestData.activityName || requestData.title,
        reason: creditNoteData.reason || 'Claim settlement',
        invoiceNumber: creditNoteData.invoiceNumber,
        sentDate: this.formatDate(creditNoteData.sentAt || new Date()),
        sentTime: this.formatTime(creditNoteData.sentAt || new Date()),
        downloadLink: creditNoteData.downloadLink,
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name
      };

      const html = getCreditNoteSentEmail(data);
      const subject = `[${requestData.requestNumber}] Credit Note Sent - ${data.creditNoteNumber}`;

      const result = await emailService.sendEmail({
        to: recipientData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 Credit Note Sent Email Preview: ${result.previewUrl}`);
      }
      logger.info(`✅ Credit Note Sent email sent to ${recipientData.email} for request ${requestData.requestNumber}`);
    } catch (error) {
      logger.error(`Failed to send Credit Note Sent email:`, error);
      throw error;
    }
  }

  /**
   * 18. Send Additional Document Added Email
   */
  async sendAdditionalDocumentAdded(
    requestData: any,
    recipientData: any,
    documentData: {
      documentName: string;
      fileSize: number;
      addedByName: string;
      source?: string; // 'Documents Tab' or 'Work Notes'
    }
  ): Promise<void> {
    try {
      const canSend = await shouldSendEmail(
        recipientData.userId,
        EmailNotificationType.ADDITIONAL_DOCUMENT_ADDED
      );

      if (!canSend) {
        logger.info(`Email skipped (preferences): Additional Document Added for ${recipientData.email}`);
        return;
      }

      // Format file size
      const formatFileSize = (bytes: number): string => {
        if (bytes < 1024) return `${bytes} B`;
        if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB`;
        return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
      };

      const data: AdditionalDocumentAddedData = {
        recipientName: recipientData.displayName || recipientData.email,
        requestId: requestData.requestNumber,
        requestTitle: requestData.title,
        documentName: documentData.documentName,
        fileSize: formatFileSize(documentData.fileSize),
        addedByName: documentData.addedByName,
        addedDate: this.formatDate(new Date()),
        addedTime: this.formatTime(new Date()),
        requestNumber: requestData.requestNumber,
        source: documentData.source,
        viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
        companyName: CompanyInfo.name
      };

      const html = getAdditionalDocumentAddedEmail(data);
      const subject = `[${requestData.requestNumber}] Additional Document Added - ${documentData.documentName}`;

      const result = await emailService.sendEmail({
        to: recipientData.email,
        subject,
        html
      });

      if (result.previewUrl) {
        logger.info(`📧 Additional Document Added Email Preview: ${result.previewUrl}`);
      }
      logger.info(`✅ Additional Document Added email sent to ${recipientData.email} for request ${requestData.requestNumber}`);
    } catch (error) {
      logger.error(`Failed to send Additional Document Added email:`, error);
      // Don't throw - email failure shouldn't block document upload
    }
  }
}

// Singleton instance
export const emailNotificationService = new EmailNotificationService();

