// Email adapter for DewLink — IMAP (read) + SMTP (send) for ANY provider (Gmail, Outlook, Yahoo,
// custom). Auth via the user's email + an app password (no OAuth). Each correspondent becomes a
// conversation (contact-centric), their emails become messages — same @@DEWLINK@@ events as WhatsApp.
//
// Env: EMAIL_USER, EMAIL_PASS, optional EMAIL_IMAP_HOST/PORT, EMAIL_SMTP_HOST/PORT.

import { ImapFlow } from "imapflow";
import { simpleParser } from "mailparser";
import nodemailer from "nodemailer";
import { emitEvent } from "./events.ts";

const USER = process.env.EMAIL_USER || "";
const PASS = process.env.EMAIL_PASS || "";

function log(level: "info" | "warn" | "error", msg: string) {
  emitEvent({ type: "log", level, msg: `[email] ${msg}` });
}

/// Best-guess IMAP/SMTP hosts from the email domain (overridable via env).
function hosts(email: string) {
  const d = (email.split("@")[1] || "").toLowerCase();
  if (d.includes("gmail") || d.includes("googlemail"))
    return { imap: { host: "imap.gmail.com", port: 993 }, smtp: { host: "smtp.gmail.com", port: 465, secure: true } };
  if (d.includes("outlook") || d.includes("hotmail") || d.includes("live") || d.includes("office365") || d.includes("msn"))
    return { imap: { host: "outlook.office365.com", port: 993 }, smtp: { host: "smtp.office365.com", port: 587, secure: false } };
  if (d.includes("yahoo") || d.includes("ymail"))
    return { imap: { host: "imap.mail.yahoo.com", port: 993 }, smtp: { host: "smtp.mail.yahoo.com", port: 465, secure: true } };
  if (d.includes("icloud") || d.includes("me.com"))
    return { imap: { host: "imap.mail.me.com", port: 993 }, smtp: { host: "smtp.mail.me.com", port: 587, secure: false } };
  return { imap: { host: `imap.${d}`, port: 993 }, smtp: { host: `smtp.${d}`, port: 465, secure: true } };
}

let client: ImapFlow | null = null;

async function emitEmail(source: Buffer, uid: number, historical: boolean) {
  try {
    const p = await simpleParser(source);
    const from = p.from?.value?.[0];
    const fromAddr = (from?.address || "unknown").toLowerCase();
    const isMe = fromAddr === USER.toLowerCase();
    // For our own sent copies the "other party" is the recipient; otherwise it's the sender.
    const toAddr = (Array.isArray(p.to) ? p.to[0]?.value?.[0]?.address : (p.to as any)?.value?.[0]?.address) || fromAddr;
    const other = (isMe ? toAddr : fromAddr).toLowerCase();
    const otherName = (isMe ? (Array.isArray(p.to) ? p.to[0]?.value?.[0]?.name : (p.to as any)?.value?.[0]?.name) : from?.name) || other;
    const subject = p.subject || "(no subject)";
    const text = (p.text || "").replace(/\s+/g, " ").trim().slice(0, 400);
    emitEvent({
      type: "message",
      convExternalId: other,
      convTitle: otherName,
      direction: isMe ? "OUT" : "IN",
      body: text ? `${subject}\n${text}` : subject,
      sender: fromAddr,
      ts: p.date ? p.date.getTime() : Date.now(),
      providerMsgId: p.messageId || `email:${uid}`,
      historical,   // initial inbox sync = true (no notify/unread); live "new mail" = false
    });
  } catch (e: any) {
    log("warn", `parse failed: ${e?.message}`);
  }
}

export async function startEmail() {
  if (!USER || !PASS) { log("error", "missing EMAIL_USER / EMAIL_PASS"); emitEvent({ type: "status", state: "logged_out" }); return; }
  const h = hosts(USER);
  const imapHost = process.env.EMAIL_IMAP_HOST || h.imap.host;
  const imapPort = Number(process.env.EMAIL_IMAP_PORT || h.imap.port);
  emitEvent({ type: "status", state: "connecting" });
  client = new ImapFlow({ host: imapHost, port: imapPort, secure: true, auth: { user: USER, pass: PASS }, logger: false });
  client.on("error", (e: any) => log("warn", `imap: ${e?.message}`));
  try {
    await client.connect();
    const mbox = await client.mailboxOpen("INBOX");
    emitEvent({ type: "status", state: "open", user: USER });
    const total = (mbox as any).exists || 0;
    const start = Math.max(1, total - 59);   // backfill the most recent ~60
    if (total > 0) {
      for await (const m of client.fetch(`${start}:*`, { source: true, uid: true })) {
        await emitEmail((m as any).source, (m as any).uid, true);   // backfill — no notify/unread
      }
    }
    log("info", `synced inbox (${total} messages)`);
    // New mail while idle.
    client.on("exists", async (data: any) => {
      try {
        const from = (data.prevCount || total) + 1;
        for await (const m of client!.fetch(`${from}:*`, { source: true, uid: true })) {
          await emitEmail((m as any).source, (m as any).uid, false);   // live new mail — notify + unread
        }
      } catch (e: any) { log("warn", `new-mail fetch: ${e?.message}`); }
    });
  } catch (e: any) {
    log("error", `connect failed: ${e?.message}`);
    emitEvent({ type: "status", state: "close" });
  }
}

/// Send an email (reply). Subject defaults to a reply marker; the recipient is the conversation id (email).
export async function sendEmail(to: string, text: string, subject?: string) {
  const h = hosts(USER).smtp;
  const t = nodemailer.createTransport({
    host: process.env.EMAIL_SMTP_HOST || h.host,
    port: Number(process.env.EMAIL_SMTP_PORT || h.port),
    secure: h.secure,
    auth: { user: USER, pass: PASS },
  });
  return t.sendMail({ from: USER, to, subject: subject || "Re:", text });
}
