const nodemailer = require('nodemailer');
const emailTemplates = require('./emailTemplates');

class EmailService {
  constructor() {
    this.transporter = null;
    this.initializeTransporter();
  }

  initializeTransporter() {
    try {
      const transporterConfig = {
        host: process.env.SMTP_HOST,
        port: parseInt(process.env.SMTP_PORT) || 587,
        secure: process.env.SMTP_PORT === '465', // true for 465, false for other ports
        tls: {
          rejectUnauthorized: false
        }
      };

      // Add auth if credentials are provided
      if (process.env.SMTP_USER && process.env.SMTP_PASS) {
        transporterConfig.auth = {
          user: process.env.SMTP_USER,
          pass: process.env.SMTP_PASS
        };
      }

      this.transporter = nodemailer.createTransport(transporterConfig);

      console.log('Email transporter initialized successfully');
    } catch (error) {
      console.error('Failed to initialize email transporter:', error);
    }
  }

  async testConnection() {
    try {
      if (!this.transporter) {
        throw new Error('Email transporter not initialized');
      }

      await this.transporter.verify();
      return {
        success: true,
        message: 'SMTP connection verified successfully'
      };
    } catch (error) {
      return {
        success: false,
        message: 'SMTP connection failed',
        error: error.message
      };
    }
  }

  async sendEmail(emailOptions, isTest = false) {
    try {
      if (!this.transporter) {
        throw new Error('Email transporter not initialized');
      }

      let to = emailOptions.to;
      let subject = emailOptions.subject;

      // Test mode - redirect emails and modify subject
      const testMode = isTest || process.env.EMAIL_TEST_MODE === 'true';
      if (testMode) {
        const originalTo = to;
        to = process.env.TEST_EMAIL_RECIPIENT || 'admin@example.com';
        subject = `[TEST - Original: ${originalTo}] ${subject}`;
        
        console.log(`Email redirected from ${originalTo} to ${to} (Test Mode)`);
      }

      const mailOptions = {
        from: `"${emailOptions.from.name}" <${emailOptions.from.email}>`,
        to: to,
        replyTo: emailOptions.replyTo,
        subject: subject,
        text: emailOptions.text,
        html: emailOptions.html
      };

      // Log email details in development
      if (process.env.NODE_ENV === 'development') {
        console.log('Email Preview:', {
          to: mailOptions.to,
          subject: mailOptions.subject,
          preview: emailOptions.text ? emailOptions.text.substring(0, 200) + '...' : 'No text content',
          testMode: testMode
        });
      }

      console.log('DEBUG: About to send email via SMTP...');
      const info = await this.transporter.sendMail(mailOptions);
      
      console.log('DEBUG: Email sent via SMTP successfully:', info.messageId);
      console.log('DEBUG: Email info response:', info.response);
      
      // Log email to database if NocoDB service is available
      console.log('DEBUG: About to log email to database...');
      try {
        await this.logEmailSent({
          to: emailOptions.to, // Log original recipient
          subject: emailOptions.subject, // Log original subject
          status: 'sent',
          messageId: info.messageId,
          testMode: testMode,
          senderName: emailOptions.from?.name || 'System',
          senderEmail: emailOptions.from?.email || process.env.SMTP_FROM_EMAIL
        });
        console.log('DEBUG: Successfully logged email to database');
      } catch (logError) {
        console.error('DEBUG: Failed to log email to database:', logError);
        // Continue anyway - don't let logging failure affect email success
      }
      
      const successResult = {
        success: true,
        messageId: info.messageId,
        response: info.response,
        testMode: testMode,
        originalRecipient: testMode ? emailOptions.to : undefined
      };
      
      console.log('DEBUG: Returning success result:', successResult);
      return successResult;
    } catch (error) {
      console.error('Email send error:', error);
      
      // Log failed email attempt
      await this.logEmailSent({
        to: emailOptions.to,
        subject: emailOptions.subject,
        status: 'failed',
        error: error.message,
        testMode: isTest || process.env.EMAIL_TEST_MODE === 'true',
        senderName: emailOptions.from?.name || 'System',
        senderEmail: emailOptions.from?.email || process.env.SMTP_FROM_EMAIL
      });
      
      return {
        success: false,
        error: error.message
      };
    }
  }

  async sendBulkEmails(emails) {
    const results = [];
    
    for (const email of emails) {
      try {
        const result = await this.sendEmail(email);
        results.push({
          to: email.to,
          success: result.success,
          messageId: result.messageId,
          error: result.error
        });
        
        // Add a small delay between emails to avoid overwhelming the SMTP server
        await new Promise(resolve => setTimeout(resolve, 1000));
      } catch (error) {
        results.push({
          to: email.to,
          success: false,
          error: error.message
        });
      }
    }
    
    return results;
  }

  formatEmailTemplate(template, data) {
    let formattedTemplate = template;
    
    // Replace placeholders with actual data
    Object.keys(data).forEach(key => {
      const placeholder = `{{${key}}}`;
      formattedTemplate = formattedTemplate.replace(new RegExp(placeholder, 'g'), data[key]);
    });
    
    return formattedTemplate;
  }

  validateEmailAddress(email) {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(email);
  }

  async logEmailSent(emailData) {
    try {
      // Use the existing logEmailSend method with the correct field structure
      const nocodbService = require('./nocodb');
      if (nocodbService && process.env.NOCODB_TABLE_EMAILS) {
        await nocodbService.logEmailSend({
          recipientEmail: emailData.to,
          senderName: emailData.senderName || 'System',
          senderEmail: emailData.senderEmail || process.env.SMTP_FROM_EMAIL,
          subject: emailData.subject,
          postalCode: emailData.postalCode || 'N/A',
          status: emailData.status || 'sent',
          timestamp: new Date().toISOString(),
          senderIP: emailData.senderIP || 'localhost'
        });
      }
    } catch (error) {
      console.error('Failed to log email:', error);
      // Don't throw - logging failure shouldn't prevent email sending
    }
  }

  async previewEmail(emailOptions) {
    // Generate email preview without sending
    return {
      to: emailOptions.to,
      subject: emailOptions.subject,
      body: emailOptions.text,
      html: emailOptions.html,
      from: `"${emailOptions.from.name}" <${emailOptions.from.email}>`,
      replyTo: emailOptions.replyTo,
      timestamp: new Date().toISOString(),
      testMode: process.env.EMAIL_TEST_MODE === 'true',
      redirectTo: process.env.EMAIL_TEST_MODE === 'true' ? process.env.TEST_EMAIL_RECIPIENT : null
    };
  }

  // Template-based email methods
  async sendTemplatedEmail(templateName, templateVariables, emailOptions, isTest = false) {
    console.log('DEBUG: sendTemplatedEmail called with template:', templateName);
    try {
      // Render the template
      console.log('DEBUG: About to render template...');
      const { html, text } = await emailTemplates.render(templateName, templateVariables);
      console.log('DEBUG: Template rendered successfully');

      // Prepare email options with rendered content
      const mailOptions = {
        ...emailOptions,
        text: text,
        html: html
      };

      // Send the email using existing sendEmail method
      console.log('DEBUG: About to call sendEmail from sendTemplatedEmail...');
      const result = await this.sendEmail(mailOptions, isTest);
      console.log('DEBUG: sendEmail returned result:', result);
      return result;
    } catch (error) {
      console.error('DEBUG: Failed to send templated email:', error);
      return {
        success: false,
        error: error.message
      };
    }
  }

  async sendRepresentativeEmail(recipientEmail, senderName, senderEmail, subject, message, postalCode, recipientName = null) {
    // Generate dynamic subject if not provided
    const finalSubject = subject || `Message from ${senderName} from ${postalCode}`;
    
    const templateVariables = {
      MESSAGE: message,
      SENDER_NAME: senderName,
      SENDER_EMAIL: senderEmail,
      POSTAL_CODE: postalCode,
      RECIPIENT_NAME: recipientName || 'Representative'
    };

    const emailOptions = {
      to: recipientEmail,
      from: {
        email: process.env.SMTP_FROM_EMAIL,
        name: process.env.SMTP_FROM_NAME
      },
      replyTo: senderEmail,
      subject: finalSubject
    };

    return await this.sendTemplatedEmail('representative-contact', templateVariables, emailOptions);
  }

  async sendCampaignEmail(recipientEmail, userEmail, userName, postalCode, subject, message, campaignTitle, recipientName = null, recipientLevel = null) {
    console.log('DEBUG: sendCampaignEmail called for recipient:', recipientEmail);
    const templateVariables = {
      MESSAGE: message,
      USER_NAME: userName,
      USER_EMAIL: userEmail,
      POSTAL_CODE: postalCode,
      CAMPAIGN_TITLE: campaignTitle,
      RECIPIENT_NAME: recipientName,
      RECIPIENT_LEVEL: recipientLevel
    };

    const emailOptions = {
      to: recipientEmail,
      from: {
        email: process.env.SMTP_FROM_EMAIL,
        name: process.env.SMTP_FROM_NAME
      },
      replyTo: userEmail,
      subject: subject
    };

    console.log('DEBUG: About to call sendTemplatedEmail from sendCampaignEmail...');
    const result = await this.sendTemplatedEmail('campaign-email', templateVariables, emailOptions);
    console.log('DEBUG: sendCampaignEmail received result:', result);
    return result;
  }

  async sendTestEmail(subject, message, testRecipient = null) {
    const recipient = testRecipient || process.env.TEST_EMAIL_RECIPIENT || 'admin@example.com';
    
    const templateVariables = {
      MESSAGE: message
    };

    const emailOptions = {
      to: recipient,
      from: {
        email: process.env.SMTP_FROM_EMAIL,
        name: process.env.SMTP_FROM_NAME
      },
      replyTo: process.env.SMTP_FROM_EMAIL,
      subject: `[TEST EMAIL] ${subject}`
    };

    return await this.sendTemplatedEmail('test-email', templateVariables, emailOptions, true);
  }

  async previewTemplatedEmail(templateName, templateVariables, emailOptions) {
    try {
      const { html, text } = await emailTemplates.render(templateName, templateVariables);
      
      return {
        to: emailOptions.to,
        subject: emailOptions.subject,
        body: text,
        html: html,
        from: `"${emailOptions.from.name}" <${emailOptions.from.email}>`,
        replyTo: emailOptions.replyTo,
        timestamp: new Date().toISOString(),
        testMode: process.env.EMAIL_TEST_MODE === 'true',
        redirectTo: process.env.EMAIL_TEST_MODE === 'true' ? process.env.TEST_EMAIL_RECIPIENT : null,
        templateName: templateName,
        templateVariables: templateVariables
      };
    } catch (error) {
      console.error('Failed to preview templated email:', error);
      throw error;
    }
  }

  // User management email methods
  async sendLoginDetails(user) {
    try {
      const baseUrl = process.env.BASE_URL || `http://localhost:${process.env.PORT || 3333}`;

      const isAdmin = user.admin || user.Admin || false;

      const templateVariables = {
        APP_NAME: 'BNKops Influence',
        USER_NAME: user.Name || user.name || user.Email || user.email,
        USER_EMAIL: user.Email || user.email,
        PASSWORD: user.Password || user.password,
        USER_ROLE: isAdmin ? 'Administrator' : 'User',
        LOGIN_URL: `${baseUrl}/login.html`,
        TIMESTAMP: new Date().toLocaleString()
      };

      const emailOptions = {
        to: user.Email || user.email,
        from: {
          email: process.env.SMTP_FROM_EMAIL,
          name: process.env.SMTP_FROM_NAME
        },
        subject: `Your Login Details - ${templateVariables.APP_NAME}`
      };

      return await this.sendTemplatedEmail('login-details', templateVariables, emailOptions);
    } catch (error) {
      console.error('Failed to send login details email:', error);
      throw error;
    }
  }
}

module.exports = new EmailService();