/**
 * Email Adapter
 *
 * Implements EmailPort using nodemailer
 */

import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as nodemailer from 'nodemailer';
import { EmailPort, EmailOptions } from '@domain/ports/out/email.port';
import { EmailTemplates } from './templates/email-templates';

@Injectable()
export class EmailAdapter implements EmailPort {
  private readonly logger = new Logger(EmailAdapter.name);
  private transporter: nodemailer.Transporter;

  constructor(
    private readonly configService: ConfigService,
    private readonly emailTemplates: EmailTemplates
  ) {
    this.initializeTransporter();
  }

  private initializeTransporter(): void {
    const host = this.configService.get<string>('SMTP_HOST', 'localhost');
    const port = this.configService.get<number>('SMTP_PORT', 2525);
    const user = this.configService.get<string>('SMTP_USER');
    const pass = this.configService.get<string>('SMTP_PASS');

    // Simple Mailtrap configuration - exactly as documented
    this.transporter = nodemailer.createTransport({
      host,
      port,
      auth: {
        user,
        pass,
      },
    });

    this.logger.log(`Email adapter initialized with SMTP host: ${host}:${port}`);
  }

  async send(options: EmailOptions): Promise<void> {
    try {
      const from = this.configService.get<string>('SMTP_FROM', 'noreply@xpeditis.com');

      await this.transporter.sendMail({
        from,
        to: options.to,
        cc: options.cc,
        bcc: options.bcc,
        replyTo: options.replyTo,
        subject: options.subject,
        html: options.html,
        text: options.text,
        attachments: options.attachments,
      });

      this.logger.log(`Email sent to ${options.to}: ${options.subject}`);
    } catch (error) {
      this.logger.error(`Failed to send email to ${options.to}`, error);
      throw error;
    }
  }

  async sendBookingConfirmation(
    email: string,
    bookingNumber: string,
    bookingDetails: any,
    pdfAttachment?: Buffer
  ): Promise<void> {
    const html = await this.emailTemplates.renderBookingConfirmation({
      bookingNumber,
      bookingDetails,
    });

    const attachments = pdfAttachment
      ? [
          {
            filename: `booking-${bookingNumber}.pdf`,
            content: pdfAttachment,
            contentType: 'application/pdf',
          },
        ]
      : undefined;

    await this.send({
      to: email,
      subject: `Booking Confirmation - ${bookingNumber}`,
      html,
      attachments,
    });
  }

  async sendVerificationEmail(email: string, token: string): Promise<void> {
    const verifyUrl = `${this.configService.get('APP_URL')}/verify-email?token=${token}`;
    const html = await this.emailTemplates.renderVerificationEmail({
      verifyUrl,
    });

    await this.send({
      to: email,
      subject: 'Verify your email - Xpeditis',
      html,
    });
  }

  async sendPasswordResetEmail(email: string, token: string): Promise<void> {
    const resetUrl = `${this.configService.get('APP_URL')}/reset-password?token=${token}`;
    const html = await this.emailTemplates.renderPasswordResetEmail({
      resetUrl,
    });

    await this.send({
      to: email,
      subject: 'Reset your password - Xpeditis',
      html,
    });
  }

  async sendWelcomeEmail(email: string, firstName: string): Promise<void> {
    const html = await this.emailTemplates.renderWelcomeEmail({
      firstName,
      dashboardUrl: `${this.configService.get('APP_URL')}/dashboard`,
    });

    await this.send({
      to: email,
      subject: 'Welcome to Xpeditis',
      html,
    });
  }

  async sendUserInvitation(
    email: string,
    organizationName: string,
    inviterName: string,
    tempPassword: string
  ): Promise<void> {
    const loginUrl = `${this.configService.get('APP_URL')}/login`;
    const html = await this.emailTemplates.renderUserInvitation({
      organizationName,
      inviterName,
      tempPassword,
      loginUrl,
    });

    await this.send({
      to: email,
      subject: `You've been invited to join ${organizationName} on Xpeditis`,
      html,
    });
  }

  async sendInvitationWithToken(
    email: string,
    firstName: string,
    lastName: string,
    organizationName: string,
    inviterName: string,
    invitationLink: string,
    expiresAt: Date
  ): Promise<void> {
    try {
      this.logger.log(`[sendInvitationWithToken] Starting email generation for ${email}`);

      const expiresAtFormatted = expiresAt.toLocaleDateString('fr-FR', {
        day: 'numeric',
        month: 'long',
        year: 'numeric',
        hour: '2-digit',
        minute: '2-digit',
      });

      this.logger.log(`[sendInvitationWithToken] Rendering template...`);
      const html = await this.emailTemplates.renderInvitationWithToken({
        firstName,
        lastName,
        organizationName,
        inviterName,
        invitationLink,
        expiresAt: expiresAtFormatted,
      });

      this.logger.log(`[sendInvitationWithToken] Template rendered, sending email to ${email}...`);
      this.logger.log(`[sendInvitationWithToken] HTML size: ${html.length} bytes`);

      await this.send({
        to: email,
        subject: `Invitation à rejoindre ${organizationName} sur Xpeditis`,
        html,
      });

      this.logger.log(`Invitation email sent to ${email} for ${organizationName}`);
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      const errorCode = (error as any).code;
      const errorResponse = (error as any).response;
      const errorResponseCode = (error as any).responseCode;
      const errorCommand = (error as any).command;

      this.logger.error(`[sendInvitationWithToken] ERROR MESSAGE: ${errorMessage}`);
      this.logger.error(`[sendInvitationWithToken] ERROR CODE: ${errorCode}`);
      this.logger.error(`[sendInvitationWithToken] ERROR RESPONSE: ${errorResponse}`);
      this.logger.error(`[sendInvitationWithToken] ERROR RESPONSE CODE: ${errorResponseCode}`);
      this.logger.error(`[sendInvitationWithToken] ERROR COMMAND: ${errorCommand}`);

      if (error instanceof Error && error.stack) {
        this.logger.error(`[sendInvitationWithToken] STACK: ${error.stack.substring(0, 500)}`);
      }

      throw error;
    }
  }

  async sendCsvBookingRequest(
    carrierEmail: string,
    bookingData: {
      bookingId: string;
      origin: string;
      destination: string;
      volumeCBM: number;
      weightKG: number;
      palletCount: number;
      priceUSD: number;
      priceEUR: number;
      primaryCurrency: string;
      transitDays: number;
      containerType: string;
      documents: Array<{
        type: string;
        fileName: string;
      }>;
      confirmationToken: string;
    }
  ): Promise<void> {
    const baseUrl = this.configService.get('APP_URL', 'http://localhost:3000');
    const acceptUrl = `${baseUrl}/api/v1/csv-bookings/${bookingData.confirmationToken}/accept`;
    const rejectUrl = `${baseUrl}/api/v1/csv-bookings/${bookingData.confirmationToken}/reject`;

    const html = await this.emailTemplates.renderCsvBookingRequest({
      ...bookingData,
      acceptUrl,
      rejectUrl,
    });

    await this.send({
      to: carrierEmail,
      subject: `Nouvelle demande de réservation - ${bookingData.origin} → ${bookingData.destination}`,
      html,
    });

    this.logger.log(
      `CSV booking request sent to ${carrierEmail} for booking ${bookingData.bookingId}`
    );
  }
}
