import logging from '../../lib/logging.js';
import { developer_admin, API } from '../../lib/api.js';
import { company } from '../../emails/config.js';
import { get_config, dns_check, send_email, load_templates } from '../../lib/email.js';

const log = logging.create(import.meta.url);

const ERRORS  = {
  ip4_double_reverse: {
    id: 0,
    title: "No IP4 Double Reverse",
    active: false,
    text: "IPv4 addresses need to have both a reverse DNS record and a matching DNS record for the host.  You have to add a reverse DNS for the IP Host address and then make sure that exact IPv4 address is listed in your DNS with a A record."
  },
  ip6_double_reverse: {
    id: 1,
    title: "No IP6 Double Reverse",
    active: false,
    text: "IPv6 addresses need to have both a reverse DNS record and a matching DNS record for the host.  You have to add a reverse DNS for the IP Host address and then make sure that exact IPv6 address is listed in your DNS with a AAAA record (not A)."
  },
  no_mx_record: {
    id: 2,
    title: "No MX Record",
    active: false,
    text: "You can run your server without an MX record but it makes it less reliable.  Add a single record with your main hostname and a 10 Priority."
  },
  spf_invalid: {
    id: 3,
    title: "SPF Record Invalid",
    active: false,
    text: "Your SPF record needs to mention both the IPv4 address with ip4:X and IPv6 address with ip6:X."
  },
  no_dmarc: {
    id: 4,
    title: "No DMARC Record",
    active: false,
    text: "You need a DMARC record, and it's recommended you configure it to p=none but route the errors to an email address on this server so you can monitor failures."
  },
  no_ip4_address: {
    id: 5,
    title: "No IP4 Address",
    active: false,
    text: "Most email providers are now requiring an IPv4 address that is also double reverse lookup, which means you need an IPv4 A record and a reverse DNS for it that exactly matches."
  },
  no_ip6_address: {
    id: 6,
    title: "No IP6 Address",
    active: false,
    text: "Most email providers are now requiring an IPv6 address that is also double reverse lookup, which means you need an IPv6 AAAA record and a reverse DNS for it that exactly matches."
  },
  no_spf: {
    id: 7,
    title: "No SPF Record",
    active: false,
    text: "You need an SPF record. It should be a TXT record and list your IP4 and IP6 addresses in the format \"v=spf1 a mx ip4:X ip6:Y ~all\"."
  },
}

const analyze_dns = (dns) => {
  let r = [];
  // consider using a Rools engine if this gets too insane
  if(dns.ip4.error) {
    r.push(ERRORS.no_ip4_address);
    r.push(ERRORS.ip4_double_reverse);
  }

  if(dns.ip4.reverse_errors) {
    r.push(ERRORS.ip4_double_reverse);
  }

  if(dns.ip6.error) {
    r.push(ERRORS.no_ip6_address);
    r.push(ERRORS.ip6_double_reverse);
  }

  if(dns.ip6.reverse_errors) {
    r.push(ERRORS.ip6_double_reverse);
  }

  if(dns.mx_error) {
    r.push(ERRORS.no_mx_record);
  }

  if(dns.spf_error) {
    r.push(ERRORS.no_spf);
  }

  if(dns.dmarc_error) {
    r.push(ERRORS.no_dmarc);
  }

  if(r.length > 1) r[0].active = true;

  return r;
}

export const get = async (req, res) => {
  const api = new API(req, res);
  const rules = { domain_name: "required"}
  const form = api.validate(rules);

  if(!api.admin_authenticated) {
    return api.error(401, "Admin rights required.");
  }

  try {
    if(form._valid) {
      const dns = await dns_check(form.domain_name);
      const tests = analyze_dns(dns);

      log.debug(dns);
      return api.reply(200, {dns, tests});
    } else {
      return api.validation_error(res, form);
    }
  } catch (error) {
    log.error(error);
    return api.error(500, "Internal Server Error");
  }
}

get.authenticated = !developer_admin;

const send_test = async (email) => {
  try {
    const test_email = await load_templates("test");
    const text = test_email.txt(email);
    const html = test_email.html(email);

    return send_email({
      from: company.mail,
      to: email,
      subject: `Test email for ${company.website}`,
      text, html
    });
  } catch(error) {
    log.error(error);
    return error;
  }
}

export const post = async (req, res) => {
  const rules = { to_address: "required|email" }
  const api = new API(req, res);

  if(!api.admin_authenticated) {
    return api.error(401, "Admin rights required.");
  }

  try {
    const form = api.validate(rules);

    if(form._valid) {
      log.debug(`Sending test email to ${form.to_address}`);
      const error = await send_test(form.to_address);

      return api.reply(200, {
        message: "Email sent. Check server logs.",
        error: error === undefined ? error : error.message,
        config: get_config()
      });
    } else {
      return api.validation_error(res, form);
    }
  } catch (error) {
    log.error(error);
    return api.error(500, "Internal Server Error");
  }
}

post.authenticated = !developer_admin;
