import { ITemplateService, TemplateInfo, TemplateValidationResult } from '../../interfaces/template.interface';
import { EmailProviderType } from '../../interfaces/email-options.interface';
import { SendGridConfig } from '../../interfaces/email-options.interface';
import { Logger } from '../../utils/logger';
import { TemplateError, InvalidTemplateError } from '../../errors';

export class SendGridTemplateService implements ITemplateService {
  private logger: Logger;


  constructor(_config: SendGridConfig) {
    this.logger = Logger.getInstance();
  }

  async renderTemplate(
    templateId: string, 
    data: Record<string, any>, 
    provider: EmailProviderType
  ): Promise<string> {
    if (provider !== EmailProviderType.SENDGRID) {
      throw new TemplateError(`Provider ${provider} not supported by SendGridTemplateService`);
    }

    try {
      this.logger.debug(`Rendering SendGrid template: ${templateId}`, { data });
      
      // In a real implementation, you would call SendGrid's template API
      // For now, we'll simulate template rendering
      const template = await this.getTemplate(templateId);
      const renderedContent = this.renderWithData(template, data);
      
      this.logger.debug(`SendGrid template rendered successfully: ${templateId}`);
      return renderedContent;
    } catch (error) {
      this.logger.error(`Failed to render SendGrid template: ${templateId}`, { error });
      throw new TemplateError(`Failed to render SendGrid template: ${templateId}`, { error });
    }
  }

  async validateTemplate(templateId: string, provider: EmailProviderType): Promise<boolean> {
    if (provider !== EmailProviderType.SENDGRID) {
      return false;
    }

    try {
      await this.getTemplate(templateId);
      return true;
    } catch {
      return false;
    }
  }

  async getTemplateInfo(templateId: string, provider: EmailProviderType): Promise<TemplateInfo> {
    if (provider !== EmailProviderType.SENDGRID) {
      throw new TemplateError(`Provider ${provider} not supported by SendGridTemplateService`);
    }

    try {
      const template = await this.getTemplate(templateId);
      
      return {
        id: templateId,
        name: template.name || templateId,
        version: template.version || '1.0.0',
        variables: template.variables || [],
        lastModified: template.updated_at ? new Date(template.updated_at) : new Date(),
        provider: EmailProviderType.SENDGRID
      };
    } catch (error) {
      throw new TemplateError(`Failed to get template info: ${templateId}`, { error });
    }
  }

  async validateTemplateWithDetails(templateId: string, data: Record<string, any>): Promise<TemplateValidationResult> {
    try {
      const template = await this.getTemplate(templateId);
      const templateVariables = template.variables || [];
      const providedVariables = Object.keys(data);
      
      const missingVariables = templateVariables.filter((v: string) => !providedVariables.includes(v));
      const warnings = providedVariables.filter((v: string) => !templateVariables.includes(v));
      
      return {
        isValid: missingVariables.length === 0,
        errors: missingVariables.length > 0 ? [`Missing required variables: ${missingVariables.join(', ')}`] : [],
        warnings: warnings.length > 0 ? [`Unused variables provided: ${warnings.join(', ')}`] : [],
        variables: templateVariables,
        missingVariables
      };
    } catch (error) {
      return {
        isValid: false,
        errors: [`Template not found or invalid: ${templateId}`],
        warnings: [],
        variables: [],
        missingVariables: []
      };
    }
  }

  private async getTemplate(templateId: string): Promise<any> {
    // In a real implementation, this would call SendGrid's template API
    // For now, we'll return a mock template structure
    if (!templateId.startsWith('d-')) {
      throw new InvalidTemplateError(`Invalid SendGrid template ID format: ${templateId}`);
    }

    // Mock template data - in production this would come from SendGrid API
    return {
      id: templateId,
      name: `Template ${templateId}`,
      version: '1.0.0',
      variables: ['name', 'activationLink', 'email'],
      updated_at: new Date().toISOString(),
      content: {
        html: '<h1>Hello {{name}}!</h1><p>Click here: {{activationLink}}</p>',
        text: 'Hello {{name}}! Click here: {{activationLink}}'
      }
    };
  }

  private renderWithData(template: any, data: Record<string, any>): string {
    // Simple template rendering - in production you might use a more sophisticated engine
    let content = template.content.html || template.content.text || '';
    
    // Replace variables with data
    Object.entries(data).forEach(([key, value]) => {
      const regex = new RegExp(`{{${key}}}`, 'g');
      content = content.replace(regex, String(value));
    });
    
    // Replace any remaining variables with empty strings
    const remainingVariables = content.match(/\{\{([^}]+)\}\}/g) || [];
    remainingVariables.forEach((variable: string) => {
      const key = variable.slice(2, -2); // Remove {{ }}
      const regex = new RegExp(`{{${key}}}`, 'g');
      content = content.replace(regex, '');
    });
    
    return content;
  }
}
