import { Request, Response } from "express";
import NewsletterService from "../../../service/club/newsletter/newsletterService";
import NewsletterFactory from "../../../factory/admin/club/newsletter/newsletter";
import NewsletterDatesService from "../../../service/club/newsletter/newsletterDatesService";
import NewsletterDatesFactory from "../../../factory/admin/club/newsletter/newsletterDates";
import NewsletterRecipientsService from "../../../service/club/newsletter/newsletterRecipientsService";
import NewsletterRecipientsFactory from "../../../factory/admin/club/newsletter/newsletterRecipients";
import { FileSystemHelper } from "../../../helpers/fileSystemHelper";
import {
  CreateNewsletterCommand,
  SynchronizeNewsletterCommand,
} from "../../../command/club/newsletter/newsletterCommand";
import NewsletterCommandHandler from "../../../command/club/newsletter/newsletterCommandHandler";
import { SynchronizeNewsletterDatesCommand } from "../../../command/club/newsletter/newsletterDatesCommand";
import NewsletterDatesCommandHandler from "../../../command/club/newsletter/newsletterDatesCommandHandler";
import { SynchronizeNewsletterRecipientsCommand } from "../../../command/club/newsletter/newsletterRecipientsCommand";
import NewsletterRecipientsCommandHandler from "../../../command/club/newsletter/newsletterRecipientsCommandHandler";
import { NewsletterDatesViewModel } from "../../../viewmodel/admin/club/newsletter/newsletterDates.models";
import { PdfExport } from "../../../helpers/pdfExport";
import UserService from "../../../service/user/userService";
import { TemplateHelper } from "../../../helpers/templateHelper";
import MailHelper from "../../../helpers/mailHelper";
import { NewsletterEventType, NewsletterHelper } from "../../../helpers/newsletterHelper";
import { Salutation } from "../../../enums/salutation";

/**
 * @description get all newsletters
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getAllNewsletters(req: Request, res: Response): Promise<any> {
  let offset = parseInt((req.query.offset as string) ?? "0");
  let count = parseInt((req.query.count as string) ?? "25");
  let [newsletters, total] = await NewsletterService.getAll(offset, count);

  res.json({
    newsletters: NewsletterFactory.mapToBase(newsletters),
    total: total,
    offset: offset,
    count: count,
  });
}

/**
 * @description get newsletter by id
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getNewsletterById(req: Request, res: Response): Promise<any> {
  let id = parseInt(req.params.id);
  let newsletter = await NewsletterService.getById(id);

  res.json(NewsletterFactory.mapToSingle(newsletter));
}

/**
 * @description get newsletter dates by id
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getNewsletterDatesById(req: Request, res: Response): Promise<any> {
  let newsletterId = parseInt(req.params.newsletterId);

  let dates = await NewsletterDatesService.getAll(newsletterId);

  res.json(NewsletterDatesFactory.mapToBase(dates));
}

/**
 * @description get newsletter recipients by id
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getNewsletterRecipientsById(req: Request, res: Response): Promise<any> {
  let newsletterId = parseInt(req.params.newsletterId);

  let recipients = await NewsletterRecipientsService.getAll(newsletterId);

  res.json(NewsletterRecipientsFactory.mapToBase(recipients));
}

/**
 * @description get newsletter printouts by id
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getNewsletterPrintoutsById(req: Request, res: Response): Promise<any> {
  let newsletterId = parseInt(req.params.newsletterId);

  let newsletter = await NewsletterService.getById(newsletterId);

  let filesInFolder = FileSystemHelper.getFilesInDirectory(
    `newsletter/${newsletter.id}_${newsletter.title.replace(" ", "")}`
  );

  res.json(filesInFolder);
}

/**
 * @description get newsletter printout by id and print
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getNewsletterPrintoutByIdAndPrint(req: Request, res: Response): Promise<any> {
  let newsletterId = parseInt(req.params.newsletterId);
  let filename = req.params.filename;

  let newsletter = await NewsletterService.getById(newsletterId);

  let filepath = FileSystemHelper.formatPath(
    "newsletter",
    `${newsletter.id}_${newsletter.title.replace(" ", "")}`,
    filename
  );

  res.sendFile(filepath, {
    headers: {
      "Content-Type": "application/pdf",
    },
  });
}

/**
 * @description create newsletter printout preview by id
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function createNewsletterPrintoutPreviewById(req: Request, res: Response): Promise<any> {
  let newsletterId = parseInt(req.params.newsletterId);
  let newsletter = await NewsletterService.getById(newsletterId);
  let dates = await NewsletterDatesService.getAll(newsletterId);
  let recipient = await UserService.getById(parseInt(req.userId));

  let data = NewsletterHelper.buildData(newsletter, dates);
  data.recipient = {
    firstname: recipient.firstname,
    lastname: recipient.lastname,
    salutation: Salutation.none,
    nameaffix: "",
    street: "Straße",
    streetNumber: "Hausnummer",
    streetNumberAdd: "Adresszusatz",
  };

  let pdf = await PdfExport.renderFile({
    title: "Probedruck Newsletter",
    template: "newsletter",
    saveToDisk: false,
    data: data,
  });

  let pdfbuffer = Buffer.from(pdf);

  res.setHeader("Content-Type", "application/pdf");
  res.setHeader("Content-Length", pdfbuffer.byteLength);
  res.setHeader("Content-Disposition", "inline; filename=preview.pdf");

  res.send(pdfbuffer);
}

/**
 * @description create newsletter
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function createNewsletter(req: Request, res: Response): Promise<any> {
  let title = req.body.title;

  let createNewsletter: CreateNewsletterCommand = {
    title,
  };
  let id = await NewsletterCommandHandler.create(createNewsletter);

  res.send(id);
}

/**
 * @description get newsletter printout progress by id
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getNewsletterPrintoutProgressById(req: Request, res: Response): Promise<any> {
  let newsletterId = parseInt(req.params.newsletterId);

  res.writeHead(200, {
    "Content-Type": "text/plain",
    "Transfer-Encoding": "chunked",
  });

  const progressHandler = (data: NewsletterEventType) => {
    if (data.newsletterId == newsletterId && data.kind == "pdf") {
      res.write(JSON.stringify(data) + "//");
    }
  };

  const completeHandler = (data: NewsletterEventType) => {
    if (data.newsletterId == newsletterId && data.kind == "pdf") {
      res.write(JSON.stringify(data));
      res.end();
    }
  };

  NewsletterHelper.jobStatus.on("progress", progressHandler);
  NewsletterHelper.jobStatus.on("complete", completeHandler);

  req.on("close", () => {
    NewsletterHelper.jobStatus.off("progress", progressHandler);
    NewsletterHelper.jobStatus.off("complete", completeHandler);
  });
}

/**
 * @description create newsletter printouts for each member by id
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function createNewsletterPrintoutById(req: Request, res: Response): Promise<any> {
  let newsletterId = parseInt(req.params.newsletterId);

  await NewsletterHelper.printPdfs(newsletterId);

  res.sendStatus(204);
}

/**
 * @description create newsletter mail preview by id
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function createNewsletterMailPreviewById(req: Request, res: Response): Promise<any> {
  let newsletterId = parseInt(req.params.newsletterId);
  let newsletter = await NewsletterService.getById(newsletterId);
  let dates = await NewsletterDatesService.getAll(newsletterId);
  let recipient = await UserService.getById(parseInt(req.userId));

  let data = NewsletterHelper.buildData(newsletter, dates);
  data.recipient = {
    firstname: recipient.firstname,
    lastname: recipient.lastname,
    salutation: Salutation.none,
    nameaffix: "",
    street: "Straße",
    streetNumber: "Hausnummer",
    streetNumberAdd: "Adresszusatz",
  };

  const { body } = await TemplateHelper.renderFileForModule({
    module: "newsletter",
    bodyData: data,
    title: "Probeversand Newsletter",
  });

  await MailHelper.sendMail(recipient.mail, "Probeversand Newsletter", body);

  res.sendStatus(204);
}

/**
 * @description send newsletter mail and create printouts by id
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function sendNewsletterById(req: Request, res: Response): Promise<any> {
  let newsletterId = parseInt(req.params.newsletterId);

  await NewsletterHelper.sendMails(newsletterId);

  res.sendStatus(204);
}

/**
 * @description get newsletter sending progress by id
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getNewsletterSendingProgressById(req: Request, res: Response): Promise<any> {
  let newsletterId = parseInt(req.params.newsletterId);

  res.writeHead(200, {
    "Content-Type": "text/plain",
    "Transfer-Encoding": "chunked",
  });

  const progressHandler = (data: NewsletterEventType) => {
    if (data.newsletterId == newsletterId && data.kind == "mail") {
      res.write(JSON.stringify(data) + "//");
    }
  };

  const completeHandler = (data: NewsletterEventType) => {
    if (data.newsletterId == newsletterId && data.kind == "mail") {
      res.write(JSON.stringify(data));
      res.end();
    }
  };

  NewsletterHelper.jobStatus.on("progress", progressHandler);
  NewsletterHelper.jobStatus.on("complete", completeHandler);

  req.on("close", () => {
    NewsletterHelper.jobStatus.off("progress", progressHandler);
    NewsletterHelper.jobStatus.off("complete", completeHandler);
  });
}

/**
 * @description synchronize newsletter by id
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function synchronizeNewsletterById(req: Request, res: Response): Promise<any> {
  let id = parseInt(req.params.id);
  let title = req.body.title;
  let description = req.body.description;
  let newsletterTitle = req.body.newsletterTitle;
  let newsletterText = req.body.newsletterText;
  let newsletterSignatur = req.body.newsletterSignatur;
  let recipientsByQueryId = req.body.recipientsByQueryId ?? null;

  let syncNewsletter: SynchronizeNewsletterCommand = {
    id,
    title,
    description,
    newsletterTitle,
    newsletterText,
    newsletterSignatur,
    recipientsByQueryId,
  };
  await NewsletterCommandHandler.sync(syncNewsletter);

  res.sendStatus(204);
}

/**
 * @description synchronize newsletter dates by id
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function synchronizeNewsletterDatesById(req: Request, res: Response): Promise<any> {
  let newsletterId = parseInt(req.params.newsletterId);
  let dates = req.body.dates as Array<NewsletterDatesViewModel>;

  let syncDates: SynchronizeNewsletterDatesCommand = {
    newsletterId,
    dates: dates.map((d) => ({
      calendarId: d.calendarId,
      diffTitle: d.diffTitle,
      diffDescription: d.diffDescription,
    })),
  };
  await NewsletterDatesCommandHandler.sync(syncDates);

  res.sendStatus(204);
}

/**
 * @description synchronize newsletter recipients by id
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function synchronizeNewsletterRecipientsById(req: Request, res: Response): Promise<any> {
  let newsletterId = parseInt(req.params.newsletterId);
  let recipients = req.body.recipients as Array<number>;

  let syncRecipients: SynchronizeNewsletterRecipientsCommand = {
    newsletterId,
    recipients: recipients,
  };
  await NewsletterRecipientsCommandHandler.sync(syncRecipients);

  res.sendStatus(204);
}