import logging from '../lib/logging.js';
import { company } from '../emails/config.js';
import { send_email, load_templates, debug_templates } from '../lib/email.js';
import { User, Payment, Product, RESET_CODE_SIZE } from "../lib/models.js";
import assert from "assert";
import differenceInHours from 'date-fns/differenceInHours/index.js';

const RESET_HOURS_MAX = 10;
const log = logging.create("/queues/mail.js");

const generic_emailer = async (name, user, mail_form, t_vars, send_vars) => {
  try {
    const text = mail_form.txt(t_vars);
    const html = mail_form.html(t_vars);

    await debug_templates({text, html}, name);
    send_vars.text = text;
    send_vars.html = html;

    // send both txt and html as attachments
    send_email(send_vars);
  } catch(err) {
    log.error(err);
  }
}

const list_unsub = (company, user) => {
  return {
    unsubscribe: {
      url: `${company.unsubscribe}${user.unsubkey}`,
      comment: "Unsubscribe"
    }
  }
}


const reset_form = await load_templates("reset_email");

export const reset = async (job) => {
  log.debug(["Received reset with", job.data]);

  try {
    assert(job.data.user, "job.data.user is required");

    const email = job.data.user.email;
    const user_id = job.data.user.id;
    const browser = job.data.browser || "None";
    const ip_address = job.data.ip_address || "None";

    assert(email, "Email is required");
    assert(user_id !== undefined, "User user_id is undefined.");

    const user = await User.first({id: user_id});

    assert(user.email === email, `Email ${email} doesn't match user ${user.id}'s email: ${user.email}`);

    if(user.reset_sent_at &&
      differenceInHours(Date.now(), user.reset_sent_at) < RESET_HOURS_MAX)
    {
      // prevent repeated high speed reset attempts by using the advanced technolog of...time
      log.warn(`User ${user.id} reset request time remaining not long enough, ignoring their request.`);
      // update the reset count so they can only attempt this a certain number of times
      await User.update({id: user.id}, { reset_count: user.reset_count + 1 });
    } else {
      // reset is good, all variables are good, so process the request

      user.reset_code = User.random_hex(RESET_CODE_SIZE);
      await User.update({id: user.id}, {reset_code: user.reset_code, reset_sent_at: Date.now()});
      const reset_data = { company, user, browser, ip_address, reset_code: user.reset_code };

      const text = reset_form.txt(reset_data);
      const html = reset_form.html(reset_data);

      await debug_templates({text, html}, "reset_email");

      // send both txt and html as attachments
      send_email({
        from: company.mail,
        to: user.email,
        list: list_unsub(company, user),
        subject: `Reset password request for ${company.website}`,
        text, html
      });
    }
  } catch(err) {
    log.error(err);
  }
}

const reset_finished_form = await load_templates("reset_finished");

export const reset_finished = async (job) => {
  try {
    const user = job.data.user;
    const browser = job.data.browser || "None";
    const ip_address = job.data.ip_address || "None";

    // update the user's password now and then send the email
    await User.update({id: user.id}, {
      password: user.password,
      reset_code: null,
      reset_sent_at: null,
      reset_count: 0
    });

    const reset_finished_data = { company, user, browser, ip_address };

    const text = reset_finished_form.txt(reset_finished_data);
    const html = reset_finished_form.html(reset_finished_data);

    await debug_templates({text, html}, "reset_finished");

    // send both txt and html as attachments
    send_email({
      from: company.mail,
      to: user.email,
      list: list_unsub(company, user),
      subject: `Reset password completed for ${company.website}`,
      text, html
    });
  } catch(err) {
    log.error(err);
  }
}

const receipt_form = await load_templates("receipt");

export const receipt = async (job) => {
  const {user, product_id, payment_id} = job.data;
  const payment = await Payment.first({id: payment_id});
  assert(payment, `Failed to find payment ID ${payment_id}`);

  const product = await Product.first({id: product_id});
  assert(product, `Failed to find course ID ${product_id}`);

  generic_emailer("receipt",
    user, receipt_form, { company, course, payment, user },
    { from: company.mail,
    to: user.email,
    list: list_unsub(company, user),
    subject: `Your ${company.product} Receipt` }
  );
}

const register_form = await load_templates("register_email");

export const registration = async (job) => {
  const user = job.data.user;

  generic_emailer("register_email",
    user, register_form, { company, user }, {
    from: company.mail,
    to: user.email,
    list: list_unsub(company, user),
    subject: `Registration for ${company.name}`
  });
}

const welcome_form = await load_templates("welcome_email");

export const welcome = async (job) => {
  const user = job.data.user;

  generic_emailer("welcome_email",
    user, welcome_form, { company, user }, {
    from: company.mail,
    to: user.email,
    list: list_unsub(company, user),
    subject: `Welcome to ${company.name}`
  });
}
