import { Injectable, Logger, InternalServerErrorException } from '@nestjs/common';
import * as amqp from 'amqplib';
import { ContactForm, Email, EmailWithoutFrom, FeedbackForm } from './email';
import { ConfigService } from '../configuration/config.service';
import { buildContactAdminEmail, buildContactUserEmail } from '../email-templates/contact';
import { buildFeedbackEmail } from '../email-templates/feedback';
import * as useragent from 'useragent';
import moment = require('moment-timezone');
moment.tz.setDefault('Europe/Paris');

@Injectable()
export class EmailService {

  private logger: Logger;
  config: any = {};

  constructor(private configService: ConfigService) {
    this.logger = new Logger(EmailService.name);
    this.config = this.configService.config;
  }

  async sendContactEmails(contactForm: ContactForm) {
    this.logger.log('Entering function', `${EmailService.name} - ${this.sendContactEmails.name}`);

    const adminEmailBody = buildContactAdminEmail({
      subject: contactForm.subject,
      message: contactForm.text,
      firstName: contactForm.firstname,
      lastName: contactForm.lastname,
      email: contactForm.email,
      datetime: moment().format('DD/MM/YYYY à HH:mm'),
      imageHost: this.config.imageHost,
    });
    const userEmailBody = buildContactUserEmail({
      subject: contactForm.subject,
      message: contactForm.text,
      firstName: contactForm.firstname,
      datetime: moment().format('DD/MM/YYYY à HH:mm'),
      imageHost: this.config.imageHost,
    });

    const adminEmail = new EmailWithoutFrom();
    adminEmail.to = [this.config.userSupportMailbox];
    adminEmail.replyTo = contactForm.email;
    adminEmail.subject = contactForm.subject;
    adminEmail.html = adminEmailBody;

    const userEmail = new EmailWithoutFrom();
    userEmail.to = [contactForm.email];
    userEmail.replyTo = this.config.userSupportMailbox;
    userEmail.subject = contactForm.subject;
    userEmail.html = userEmailBody;

    await this.send(adminEmail);
    await this.send(userEmail);

    return;
  }

  async sendFeedback(feedbackForm: FeedbackForm, userAgent) {
    this.logger.log('Entering function', `${EmailService.name} - ${this.sendFeedback.name}`);

    const userAgentParsed = useragent.parse(userAgent);
    let userAgentString = '';

    if (userAgentParsed) {
      userAgentString = `Family: ${userAgentParsed.family},`;
      userAgentString += `Version:${userAgentParsed.major}.${userAgentParsed.minor}.${userAgentParsed.patch},`;
      userAgentString += `Source: ${userAgentParsed.source}`;
    }

    const feedbackEmailBody = buildFeedbackEmail({
      url: feedbackForm.url,
      userAgent: userAgentString,
      version: feedbackForm.version,
      message: feedbackForm.message,
      datetime: moment().format('DD/MM/YYYY à HH:mm'),
      imageHost: this.config.imageHost,
    });
    const feedbackEmail = new EmailWithoutFrom();
    feedbackEmail.to = [this.config.userSupportMailbox];

    if (this.config.additionalFeedbackEmails) {
      feedbackEmail.to = feedbackEmail.to.concat(this.config.additionalFeedbackEmails.split(','));
    }

    feedbackEmail.subject = 'Feedback';
    feedbackEmail.html = feedbackEmailBody;

    await this.send(feedbackEmail);

    return;
  }

  async send(emailInfo: EmailWithoutFrom) {
    this.logger.log('Entering function', `${EmailService.name} - ${this.send.name}`);

    let conn, ch;
    // tslint:disable-next-line:max-line-length
    const rabbitmqUrl = `amqp://${this.config.rabbitMQ.user}:${this.config.rabbitMQ.password}@${this.config.rabbitMQ.host}:${this.config.rabbitMQ.port}`;
    const mailerQueue = this.config.mailerQueue;

    let email = new Email();
    email.from = this.config.noReplyMailAddress;
    email = Object.assign(email, emailInfo);

    if (this.config.mailSubjectPrefix) {
      email.subject = `[${this.config.mailSubjectPrefix}] ${email.subject}`;
    }

    // Connect to rabbitmq
    try {
      conn = await amqp.connect(rabbitmqUrl);
    } catch (error) {
      this.logger.error('Error connecting to RabbitMQ', error, `${EmailService.name} - ${this.send.name}`);
      throw new InternalServerErrorException('Could not connect to rabbitMQ.');
    }

    try {
      // Create a communication channel
      ch = await conn.createChannel();
    } catch (error) {
      this.logger.error('Error creating channel', error, `${EmailService.name} - ${this.send.name}`);
      throw new InternalServerErrorException('Could not create channel.');
    }

    // Stringify and bufferise message
    const buffer = Buffer.from(JSON.stringify(email));

    try {
      await ch.assertQueue(mailerQueue, { durable: true });
    } catch (error) {
      this.logger.error('Error asserting queue', error, `${EmailService.name} - ${this.send.name}`);
      throw new InternalServerErrorException('Could not assert queue.');
    }

    try {
      await ch.sendToQueue(mailerQueue, buffer, { persistent: true });
    } catch (error) {
      this.logger.error('Error sending to queue', error, `${EmailService.name} - ${this.send.name}`);
      throw new InternalServerErrorException('Could not send to queue.');
    }

    this.logger.log(
      `Sent to queue ${mailerQueue},{ from: ${email.from}, to: ${email.to}, subject: ${email.subject}}`, `${EmailService.name} - ${this.send.name}`,
    );

    setTimeout(() => { conn.close(); }, 500);
    return;
  }

}