const nodemailer = require('nodemailer');
const config = require('../config');
const { query, pool } = require('../db');

/**
 * Service for sending emails with templates
 */
const emailService = {
  /**
   * Create email transporter
   * @returns {Object} Configured nodemailer transporter
   */
  createTransporter() {
    return nodemailer.createTransport({
      host: config.email.host,
      port: config.email.port,
      auth: {
        user: config.email.user,
        pass: config.email.pass
      }
    });
  },

  /**
   * Get a template by type, preferring the default one
   * @param {string} type - Template type
   * @returns {Promise<Object|null>} Template object or null if not found
   */
  async getTemplateByType(type) {
    try {
      // Get all settings with 'email_templates' category
      const result = await query(
        'SELECT * FROM system_settings WHERE category = $1',
        ['email_templates']
      );
      
      // Find the default template for the specified type
      let defaultTemplate = null;
      let fallbackTemplate = null;
      
      for (const setting of result.rows) {
        try {
          console.log(setting.value, typeof setting.value)
          const templateData = JSON.parse(setting.value);
          
          if (templateData.type === type) {
            if (templateData.isDefault) {
              defaultTemplate = {
                id: setting.key,
                ...templateData
              };
              break; // Found the default template
            } else if (!fallbackTemplate) {
              // Keep a fallback template in case no default is found
              fallbackTemplate = {
                id: setting.key,
                ...templateData
              };
            }
          }
        } catch (e) {
          console.error(`Failed to parse template setting: ${setting.key}`, e);
        }
      }
      
      // Return default template if found, otherwise return fallback or null
      return defaultTemplate || fallbackTemplate || null;
    } catch (error) {
      console.error('Error getting template by type:', error);
      return null;
    }
  },

  /**
   * Replace template variables with actual values
   * @param {string} content - Template content
   * @param {Object} variables - Variable values
   * @returns {string} Processed content
   */
  replaceVariables(content, variables) {
    let processedContent = content;
    
    if (variables) {
      for (const [key, value] of Object.entries(variables)) {
        const placeholder = `{{${key}}}`;
        const regex = new RegExp(placeholder, 'g');
        processedContent = processedContent.replace(regex, value || '');
      }
    }
    
    return processedContent;
  },

  /**
   * Send an email using a template
   * @param {Object} options - Email options
   * @param {string} options.to - Recipient email address
   * @param {string} options.templateType - Template type
   * @param {Object} options.variables - Template variables
   * @param {string} [options.from] - Sender email (optional, defaults to config)
   * @param {string} [options.subject] - Custom subject (optional, defaults to template subject)
   * @param {string} [options.cc] - CC recipients (optional)
   * @param {string} [options.bcc] - BCC recipients (optional)
   * @returns {Promise<boolean>} Success status
   */
  async sendTemplatedEmail(options) {
    try {
      const { to, templateType, variables, from, subject, cc, bcc } = options;
      
      // Get template
      const template = await this.getTemplateByType(templateType);
      
      if (!template) {
        throw new Error(`No template found for type: ${templateType}`);
      }
      
      // Replace variables in content and subject
      const emailContent = this.replaceVariables(template.content, variables);
      const emailSubject = subject || this.replaceVariables(template.subject, variables);
      
      // Create transporter
      const transporter = this.createTransporter();
      
      // Send email
      const result = await transporter.sendMail({
        from: from || config.email.reply,
        to,
        cc,
        bcc,
        subject: emailSubject,
        html: emailContent
      });
      
      console.log(`Email sent: ${result.messageId}`);
      return true;
    } catch (error) {
      console.error('Error sending templated email:', error);
      throw error;
    }
  },

  /**
   * Send a login code email
   * @param {Object} options - Options
   * @param {string} options.to - Recipient email
   * @param {string} options.code - Login verification code
   * @param {string} options.loginLink - Direct login link
   * @returns {Promise<boolean>} Success status
   */
  async sendLoginCodeEmail(options) {
    const { to, code, loginLink } = options;
    
    return this.sendTemplatedEmail({
      to,
      templateType: 'login_code',
      variables: {
        code,
        loginLink,
        email: to
      }
    });
  },

  /**
   * Send a shipping notification email
   * @param {Object} options - Options
   * @param {string} options.to - Recipient email
   * @param {string} options.first_name - Customer's first name
   * @param {string} options.order_id - Order ID
   * @param {string} options.tracking_number - Tracking number
   * @param {string} options.carrier - Shipping carrier
   * @param {string} options.tracking_link - Tracking link
   * @param {string} options.shipped_date - Ship date
   * @param {string} options.estimated_delivery - Estimated delivery
   * @param {string} options.items_html - Order items HTML table
   * @param {string} options.customer_message - Custom message
   * @returns {Promise<boolean>} Success status
   */
  async sendShippingNotification(options) {
    return this.sendTemplatedEmail({
      to: options.to,
      templateType: 'shipping_notification',
      variables: options
    });
  },

  /**
   * Send an order confirmation email
   * @param {Object} options - Options
   * @param {string} options.to - Recipient email
   * @param {string} options.first_name - Customer's first name
   * @param {string} options.order_id - Order ID
   * @param {string} options.order_date - Order date
   * @param {string} options.order_total - Order total
   * @param {string} options.shipping_address - Shipping address
   * @param {string} options.items_html - Order items HTML table
   * @returns {Promise<boolean>} Success status
   */
  async sendOrderConfirmation(options) {
    return this.sendTemplatedEmail({
      to: options.to,
      templateType: 'order_confirmation',
      variables: options
    });
  },

  /**
   * Send a low stock alert email
   * @param {Object} options - Options
   * @param {string} options.to - Recipient email
   * @param {string} options.product_name - Product name
   * @param {string} options.current_stock - Current stock level
   * @param {string} options.threshold - Stock threshold
   * @returns {Promise<boolean>} Success status
   */
  async sendLowStockAlert(options) {
    return this.sendTemplatedEmail({
      to: options.to,
      templateType: 'low_stock_alert',
      variables: options
    });
  },

  /**
   * Send a welcome email
   * @param {Object} options - Options
   * @param {string} options.to - Recipient email
   * @param {string} options.first_name - User's first name
   * @returns {Promise<boolean>} Success status
   */
  async sendWelcomeEmail(options) {
    return this.sendTemplatedEmail({
      to: options.to,
      templateType: 'welcome_email',
      variables: {
        first_name: options.first_name,
        email: options.to
      }
    });
  },

  /**
   * Log an email in the database
   * @param {Object} emailData - Email data to log
   * @param {string} emailData.recipient - Recipient email
   * @param {string} emailData.subject - Email subject
   * @param {string} emailData.sent_by - User ID who sent the email
   * @param {string} [emailData.template_id] - Template ID used
   * @param {string} [emailData.template_type] - Template type used
   * @returns {Promise<Object>} Log entry
   */
  async logEmail(emailData) {
    try {
      const result = await query(
        `INSERT INTO email_logs 
         (recipient, subject, sent_by, template_id, template_type, status) 
         VALUES ($1, $2, $3, $4, $5, $6)
         RETURNING *`,
        [
          emailData.recipient,
          emailData.subject,
          emailData.sent_by,
          emailData.template_id || null,
          emailData.template_type || null,
          'sent'
        ]
      );
      
      return result.rows[0];
    } catch (error) {
      console.error('Error logging email:', error);
      // Don't throw error, just log it
      return null;
    }
  }
};

module.exports = emailService;