import * as plugins from '../../plugins.js';
import * as paths from '../../paths.js';
import { logger } from '../../logger.js';
import { Email, type IEmailOptions, type IAttachment } from './classes.email.js';

/**
 * Email template type definition
 */
export interface IEmailTemplate<T = any> {
  id: string;
  name: string;
  description: string;
  from: string;
  subject: string;
  bodyHtml: string;
  bodyText?: string;
  category?: string;
  sampleData?: T;
  attachments?: Array<{
    name: string;
    path: string;
    contentType?: string;
  }>;
}

/**
 * Email template context - data used to render the template
 */
export interface ITemplateContext {
  [key: string]: any;
}

/**
 * Template category definitions
 */
export enum TemplateCategory {
  NOTIFICATION = 'notification',
  TRANSACTIONAL = 'transactional',
  MARKETING = 'marketing',
  SYSTEM = 'system'
}

/**
 * Enhanced template manager using Email class for template rendering
 */
export class TemplateManager {
  private templates: Map<string, IEmailTemplate> = new Map();
  private defaultConfig: {
    from: string;
    replyTo?: string;
    footerHtml?: string;
    footerText?: string;
  };
  
  constructor(defaultConfig?: {
    from?: string;
    replyTo?: string;
    footerHtml?: string;
    footerText?: string;
  }) {
    // Set default configuration
    this.defaultConfig = {
      from: defaultConfig?.from || 'noreply@mail.lossless.com',
      replyTo: defaultConfig?.replyTo,
      footerHtml: defaultConfig?.footerHtml || '',
      footerText: defaultConfig?.footerText || ''
    };
    
    // Initialize with built-in templates
    this.registerBuiltinTemplates();
  }
  
  /**
   * Register built-in email templates
   */
  private registerBuiltinTemplates(): void {
    // Welcome email
    this.registerTemplate<{
      firstName: string;
      accountUrl: string;
    }>({
      id: 'welcome',
      name: 'Welcome Email',
      description: 'Sent to users when they first sign up',
      from: this.defaultConfig.from,
      subject: 'Welcome to {{serviceName}}!',
      category: TemplateCategory.TRANSACTIONAL,
      bodyHtml: `
        <h1>Welcome, {{firstName}}!</h1>
        <p>Thank you for joining {{serviceName}}. We're excited to have you on board.</p>
        <p>To get started, <a href="{{accountUrl}}">visit your account</a>.</p>
      `,
      bodyText: 
        `Welcome, {{firstName}}!
        
        Thank you for joining {{serviceName}}. We're excited to have you on board.
        
        To get started, visit your account: {{accountUrl}}
        `,
      sampleData: {
        firstName: 'John',
        accountUrl: 'https://example.com/account'
      }
    });
    
    // Password reset
    this.registerTemplate<{
      resetUrl: string;
      expiryHours: number;
    }>({
      id: 'password-reset',
      name: 'Password Reset',
      description: 'Sent when a user requests a password reset',
      from: this.defaultConfig.from,
      subject: 'Password Reset Request',
      category: TemplateCategory.TRANSACTIONAL,
      bodyHtml: `
        <h2>Password Reset Request</h2>
        <p>You recently requested to reset your password. Click the link below to reset it:</p>
        <p><a href="{{resetUrl}}">Reset Password</a></p>
        <p>This link will expire in {{expiryHours}} hours.</p>
        <p>If you didn't request a password reset, please ignore this email.</p>
      `,
      sampleData: {
        resetUrl: 'https://example.com/reset-password?token=abc123',
        expiryHours: 24
      }
    });
    
    // System notification
    this.registerTemplate({
      id: 'system-notification',
      name: 'System Notification',
      description: 'General system notification template',
      from: this.defaultConfig.from,
      subject: '{{subject}}',
      category: TemplateCategory.SYSTEM,
      bodyHtml: `
        <h2>{{title}}</h2>
        <div>{{message}}</div>
      `,
      sampleData: {
        subject: 'Important System Notification',
        title: 'System Maintenance',
        message: 'The system will be undergoing maintenance on Saturday from 2-4am UTC.'
      }
    });
  }
  
  /**
   * Register a new email template
   * @param template The email template to register
   */
  public registerTemplate<T = any>(template: IEmailTemplate<T>): void {
    if (this.templates.has(template.id)) {
      logger.log('warn', `Template with ID '${template.id}' already exists and will be overwritten`);
    }
    
    // Add footer to templates if configured
    if (this.defaultConfig.footerHtml && template.bodyHtml) {
      template.bodyHtml += this.defaultConfig.footerHtml;
    }
    
    if (this.defaultConfig.footerText && template.bodyText) {
      template.bodyText += this.defaultConfig.footerText;
    }
    
    this.templates.set(template.id, template);
    logger.log('info', `Registered email template: ${template.id}`);
  }
  
  /**
   * Get an email template by ID
   * @param templateId The template ID
   * @returns The template or undefined if not found
   */
  public getTemplate<T = any>(templateId: string): IEmailTemplate<T> | undefined {
    return this.templates.get(templateId) as IEmailTemplate<T>;
  }
  
  /**
   * List all available templates
   * @param category Optional category filter
   * @returns Array of email templates
   */
  public listTemplates(category?: TemplateCategory): IEmailTemplate[] {
    const templates = Array.from(this.templates.values());
    if (category) {
      return templates.filter(template => template.category === category);
    }
    return templates;
  }
  
  /**
   * Create an Email instance from a template
   * @param templateId The template ID
   * @param context The template context data
   * @returns A configured Email instance
   */
  public async createEmail<T = any>(
    templateId: string,
    context?: ITemplateContext
  ): Promise<Email> {
    const template = this.getTemplate(templateId);
    
    if (!template) {
      throw new Error(`Template with ID '${templateId}' not found`);
    }
    
    // Build attachments array for Email
    const attachments: IAttachment[] = [];
    
    if (template.attachments && template.attachments.length > 0) {
      for (const attachment of template.attachments) {
        try {
          const attachmentPath = plugins.path.isAbsolute(attachment.path) 
            ? attachment.path 
            : plugins.path.join(paths.MtaAttachmentsDir, attachment.path);
            
          // Read the file
          const fileBuffer = await plugins.fs.promises.readFile(attachmentPath);
          
          attachments.push({
            filename: attachment.name,
            content: fileBuffer,
            contentType: attachment.contentType || 'application/octet-stream'
          });
        } catch (error) {
          logger.log('error', `Failed to add attachment '${attachment.name}': ${error.message}`);
        }
      }
    }
    
    // Create Email instance with template content
    const emailOptions: IEmailOptions = {
      from: template.from || this.defaultConfig.from,
      subject: template.subject,
      text: template.bodyText || '',
      html: template.bodyHtml,
      // Note: 'to' is intentionally omitted for templates
      attachments,
      variables: context || {}
    };
    
    return new Email(emailOptions);
  }
  
  /**
   * Create and completely process an Email instance from a template
   * @param templateId The template ID
   * @param context The template context data
   * @returns A complete, processed Email instance ready to send
   */
  public async prepareEmail<T = any>(
    templateId: string,
    context: ITemplateContext = {}
  ): Promise<Email> {
    const email = await this.createEmail<T>(templateId, context);
    
    // Email class processes variables when needed, no pre-compilation required
    
    return email;
  }
  
  /**
   * Create a MIME-formatted email from a template
   * @param templateId The template ID
   * @param context The template context data
   * @returns A MIME-formatted email string
   */
  public async createMimeEmail(
    templateId: string,
    context: ITemplateContext = {}
  ): Promise<string> {
    const email = await this.prepareEmail(templateId, context);
    return email.toRFC822String(context);
  }
  
  
  /**
   * Load templates from a directory
   * @param directory The directory containing template JSON files
   */
  public async loadTemplatesFromDirectory(directory: string): Promise<void> {
    try {
      // Ensure directory exists
      if (!plugins.fs.existsSync(directory)) {
        logger.log('error', `Template directory does not exist: ${directory}`);
        return;
      }
      
      // Get all JSON files
      const files = plugins.fs.readdirSync(directory)
        .filter(file => file.endsWith('.json'));
      
      for (const file of files) {
        try {
          const filePath = plugins.path.join(directory, file);
          const content = plugins.fs.readFileSync(filePath, 'utf8');
          const template = JSON.parse(content) as IEmailTemplate;
          
          // Validate template
          if (!template.id || !template.subject || (!template.bodyHtml && !template.bodyText)) {
            logger.log('warn', `Invalid template in ${file}: missing required fields`);
            continue;
          }
          
          this.registerTemplate(template);
        } catch (error) {
          logger.log('error', `Error loading template from ${file}: ${error.message}`);
        }
      }
      
      logger.log('info', `Loaded ${this.templates.size} email templates`);
    } catch (error) {
      logger.log('error', `Failed to load templates from directory: ${error.message}`);
      throw error;
    }
  }
}