import { createClient } from "https://esm.sh/@supabase/supabase-js@2";

type SenderConfig = {
  host: string;
  port?: number;
  username: string;
  password: string;
  use_tls?: boolean;
  use_ssl?: boolean;
  from: string;
  fromEmail?: string;
  fromName?: string;
  envelopeFrom?: string;
  signature_html?: string;
};

const corsHeaders = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Headers":
    "authorization, x-client-info, apikey, content-type, x-supabase-client-platform, x-supabase-client-platform-version, x-supabase-client-runtime, x-supabase-client-runtime-version",
};

const FALLBACK_PUBLIC_SUPABASE_URL = "https://yqdefzjapnzabowsgoyd.supabase.co";

function getPublicFunctionBaseUrl() {
  const explicitUrl = Deno.env.get("PUBLIC_SUPABASE_URL") || Deno.env.get("PUBLIC_FUNCTION_BASE_URL") || Deno.env.get("VITE_SUPABASE_URL");
  if (explicitUrl) return explicitUrl.replace(/\/$/, "");

  const internalUrl = (Deno.env.get("SUPABASE_URL") || "").replace(/\/$/, "");
  if (/^https:\/\/[^/]+\.supabase\.co$/i.test(internalUrl)) return internalUrl;

  const projectRef = Deno.env.get("SUPABASE_PROJECT_REF") || Deno.env.get("SB_PROJECT_REF");
  if (projectRef) return `https://${projectRef}.supabase.co`;

  return FALLBACK_PUBLIC_SUPABASE_URL;
}

const ALLOWED_ROLES = ["admin", "manager", "staff", "employee", "board_member", "arc_member", "fining_member"] as const;

function jsonResponse(body: unknown, status = 200) {
  return new Response(JSON.stringify(body), {
    status,
    headers: { ...corsHeaders, "Content-Type": "application/json" },
  });
}

async function getAuthorizedCaller(req: Request) {
  const authHeader = req.headers.get("authorization") || "";
  if (!authHeader.startsWith("Bearer ")) {
    return { error: jsonResponse({ success: false, error: "Unauthorized" }, 401) };
  }

  const supabaseUrl = Deno.env.get("SUPABASE_URL")!;
  const anonKey = Deno.env.get("SUPABASE_ANON_KEY")!;
  const callerClient = createClient(supabaseUrl, anonKey, {
    global: { headers: { Authorization: authHeader } },
  });

  const token = authHeader.replace("Bearer ", "");
  const { data: claimsData, error: claimsError } = await callerClient.auth.getClaims(token);
  const callerId = claimsData?.claims?.sub;

  if (claimsError || !callerId) {
    console.error("[send-smtp-email] Auth failed - claimsError:", claimsError?.message, "callerId:", callerId);
    return { error: jsonResponse({ success: false, error: "Unauthorized" }, 401) };
  }

  console.log("[send-smtp-email] Authenticated user:", callerId);

  for (const role of ALLOWED_ROLES) {
    const { data: hasRole } = await callerClient.rpc("has_role", {
      _user_id: callerId,
      _role: role,
    });

    if (hasRole) {
      console.log("[send-smtp-email] User has role:", role);
      return { callerId, authHeader };
    }
  }

  console.error("[send-smtp-email] No matching role found for user:", callerId);
  return { error: jsonResponse({ success: false, error: "Insufficient permissions" }, 403) };
}

async function getAuthenticatedCaller(req: Request) {
  const authHeader = req.headers.get("authorization") || "";
  if (!authHeader.startsWith("Bearer ")) {
    return { error: jsonResponse({ success: false, error: "Unauthorized" }, 401) };
  }

  const supabaseUrl = Deno.env.get("SUPABASE_URL")!;
  const anonKey = Deno.env.get("SUPABASE_ANON_KEY")!;
  const callerClient = createClient(supabaseUrl, anonKey, {
    global: { headers: { Authorization: authHeader } },
  });

  const token = authHeader.replace("Bearer ", "");
  const { data: claimsData, error: claimsError } = await callerClient.auth.getClaims(token);
  const callerId = claimsData?.claims?.sub;

  if (claimsError || !callerId) {
    return { error: jsonResponse({ success: false, error: "Unauthorized" }, 401) };
  }

  return { callerId };
}

function escapeHtml(value: string) {
  return String(value ?? "")
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#39;");
}

function mapSenderRowToConfig(sender: any): SenderConfig {
  const port = Number(sender.smtp_port ?? 587);
  const isImplicitSslPort = port === 465;
  const isStartTlsPort = port === 587;
  const envelopeFrom = sender.smtp_username || sender.email_address;

  return {
    host: sender.smtp_host,
    port,
    username: sender.smtp_username,
    password: sender.smtp_password,
    use_ssl: isImplicitSslPort ? true : sender.use_ssl ?? false,
    use_tls: isImplicitSslPort ? false : sender.use_tls ?? isStartTlsPort,
    from: sender.sender_name
      ? `${sender.sender_name} <${sender.email_address}>`
      : sender.email_address,
    fromEmail: sender.email_address,
    fromName: sender.sender_name,
    envelopeFrom,
    signature_html: sender.signature_html || "",
  };
}

function ensureHtmlDocument(htmlContent: string) {
  const trimmed = String(htmlContent ?? "").trim();

  if (!trimmed) return "<!DOCTYPE html><html><body></body></html>";
  if (/<!doctype html/i.test(trimmed) || /<html[\s>]/i.test(trimmed)) return trimmed;

  return `<!DOCTYPE html><html><body>${trimmed}</body></html>`;
}

function toPlainText(htmlContent: string) {
  return htmlContent
    .replace(/<\s*br\s*\/?>/gi, "\n")
    .replace(/<\/(p|div|h1|h2|h3|h4|h5|h6|li|tr|section)\s*>/gi, "\n")
    .replace(/<style[\s\S]*?<\/style>/gi, "")
    .replace(/<script[\s\S]*?<\/script>/gi, "")
    .replace(/<[^>]+>/g, "")
    .replace(/&nbsp;/gi, " ")
    .replace(/&amp;/gi, "&")
    .replace(/&lt;/gi, "<")
    .replace(/&gt;/gi, ">")
    .replace(/\r\n/g, "\n")
    .replace(/\n{3,}/g, "\n\n")
    .trim();
}

function toBase64Utf8(value: string) {
  const bytes = new TextEncoder().encode(value);
  let binary = "";
  for (let i = 0; i < bytes.length; i++) {
    binary += String.fromCharCode(bytes[i]);
  }
  return btoa(binary);
}

function chunkBase64(value: string, lineLength = 76) {
  const lines: string[] = [];
  for (let i = 0; i < value.length; i += lineLength) {
    lines.push(value.slice(i, i + lineLength));
  }
  return lines.join("\r\n");
}

function sanitizeHeaderValue(value: string) {
  return String(value ?? "")
    .replace(/[\r\n]+/g, " ")
    .trim();
}

function extractEmailAddress(value: string) {
  const sanitized = sanitizeHeaderValue(value);
  const bracketMatch = sanitized.match(/<([^>]+)>/);
  if (bracketMatch?.[1]) return bracketMatch[1].trim();
  return sanitized;
}

function extractDisplayName(value: string) {
  const sanitized = sanitizeHeaderValue(value);
  const bracketIndex = sanitized.indexOf("<");
  if (bracketIndex <= 0) return "";
  return sanitized.slice(0, bracketIndex).trim().replace(/^"|"$/g, "");
}

function formatAddressHeader(email: string, displayName?: string) {
  const safeEmail = sanitizeHeaderValue(email);
  const safeName = sanitizeHeaderValue(displayName || "");

  if (!safeName) return safeEmail;

  const escapedName = safeName.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
  const needsQuotes = /[",;<>@\[\]\(\):]/.test(escapedName);
  return needsQuotes
    ? `"${escapedName}" <${safeEmail}>`
    : `${escapedName} <${safeEmail}>`;
}

function normalizeRecipients(recipients: string[]) {
  return recipients
    .map((recipient) => sanitizeHeaderValue(recipient))
    .filter(Boolean);
}

function dotStuffSmtpData(content: string) {
  const normalized = content.replace(/\r?\n/g, "\r\n");
  return normalized.replace(/(^|\r\n)\./g, "$1..");
}

function buildSenderKey(sender: any) {
  return `${String(sender.email_address ?? "").trim().toLowerCase()}::${String(sender.smtp_username ?? "").trim().toLowerCase()}`;
}

function sortSendersForDisplay(a: any, b: any) {
  const defaultDiff = Number(Boolean(b.is_default)) - Number(Boolean(a.is_default));
  if (defaultDiff !== 0) return defaultDiff;

  const verifiedDiff = Number(Boolean(b.verified)) - Number(Boolean(a.verified));
  if (verifiedDiff !== 0) return verifiedDiff;

  return new Date(b.updated_at ?? 0).getTime() - new Date(a.updated_at ?? 0).getTime();
}

const senderSelectFields = "id, sender_name, email_address, smtp_host, smtp_port, smtp_username, smtp_password, use_tls, use_ssl, is_active, verified, is_default, updated_at, signature_html";

async function resolveLatestSenderVariant(adminClient: any, sender: any) {
  const normalizedEmail = String(sender?.email_address ?? "").trim().toLowerCase();
  const normalizedUsername = String(sender?.smtp_username ?? "").trim().toLowerCase();

  if (!normalizedEmail || !normalizedUsername) {
    return sender;
  }

  const { data: matchingSenders, error } = await adminClient
    .from("email_senders")
    .select(senderSelectFields)
    .eq("is_active", true)
    .eq("email_address", normalizedEmail)
    .eq("smtp_username", normalizedUsername)
    .order("updated_at", { ascending: false });

  if (error || !matchingSenders?.length) {
    return sender;
  }

  const [latestSender] = matchingSenders.sort((a: any, b: any) => new Date(b.updated_at ?? 0).getTime() - new Date(a.updated_at ?? 0).getTime());

  if (latestSender?.id && latestSender.id !== sender.id) {
    console.log("[send-smtp-email] Replaced stale sender", sender.id, "with latest sender", latestSender.id);
  }

  return latestSender ?? sender;
}

async function resolveSender(payload: any, adminClient: any, req: Request) {
  if (payload.sender_id) {
    const auth = await getAuthorizedCaller(req);
    if (auth.error) return auth;

    const { data: sender, error } = await adminClient
      .from("email_senders")
      .select(senderSelectFields)
      .eq("id", payload.sender_id)
      .maybeSingle();

    if (error || !sender) {
      return { error: jsonResponse({ success: false, error: "Sender not found or inactive. Please update your sender in Email Settings." }, 404) };
    }

    const freshestSender = await resolveLatestSenderVariant(adminClient, sender);

    if (!freshestSender?.is_active) {
      return { error: jsonResponse({ success: false, error: "Sender not found or inactive. Please update your sender in Email Settings." }, 404) };
    }

    return { sender: mapSenderRowToConfig(freshestSender), callerId: auth.callerId };
  }

  if (payload.sender) {
    return { sender: payload.sender, callerId: payload.fallback_user_id ?? null };
  }

  return { error: jsonResponse({ success: false, error: "Missing sender configuration" }, 400) };
}

const SMTP_CONNECT_TIMEOUT_MS = 20000;
const SMTP_COMMAND_TIMEOUT_MS = 30000;

async function withTimeout<T>(promise: Promise<T>, timeoutMs: number, timeoutMessage: string): Promise<T> {
  let timeoutId: number | undefined;

  try {
    return await new Promise<T>((resolve, reject) => {
      timeoutId = setTimeout(() => reject(new Error(timeoutMessage)), timeoutMs);
      promise.then(resolve).catch(reject);
    });
  } finally {
    if (timeoutId !== undefined) clearTimeout(timeoutId);
  }
}

async function sendViaSMTP(
  sender: SenderConfig,
  toList: string[],
  ccList: string[],
  bccList: string[],
  subject: string,
  htmlContent: string,
  attachments: any[],
  debug: boolean
): Promise<{ success: boolean; error?: string; diagnosticLogs: string[]; smtpResponse?: string }> {
  const {
    host,
    port = 587,
    username,
    password,
    use_tls = true,
    use_ssl = false,
    from,
    fromEmail,
    fromName,
    envelopeFrom,
  } = sender;
  const diagnosticLogs: string[] = [];

  if (!host || !username || !password || !from) {
    return { success: false, error: "Incomplete sender configuration (missing host, username, password, or from address)", diagnosticLogs };
  }

  const boundary = `----=_Part_${crypto.randomUUID().replace(/-/g, "")}`;
  const alternativeBoundary = `----=_Alt_${crypto.randomUUID().replace(/-/g, "")}`;
  let mimeMessage = "";
  const hasAttachments = Array.isArray(attachments) && attachments.length > 0;
  const resolvedFromEmail = sanitizeHeaderValue(
    fromEmail || envelopeFrom || username || extractEmailAddress(from)
  );
  const resolvedFromName = sanitizeHeaderValue(fromName || extractDisplayName(from));
  const fromHeader = formatAddressHeader(resolvedFromEmail, resolvedFromName);
  const safeHtmlContent = ensureHtmlDocument(htmlContent);
  const plainTextContent = toPlainText(safeHtmlContent) || subject;
  const messageIdDomain = resolvedFromEmail.includes("@") ? resolvedFromEmail.split("@")[1] : host;
  const messageId = `<${crypto.randomUUID()}@${messageIdDomain}>`;
  const safeSubject = sanitizeHeaderValue(subject);
  const normalizedToList = normalizeRecipients(toList);
  const normalizedCcList = normalizeRecipients(ccList);
  const normalizedBccList = normalizeRecipients(bccList);

  const headers: string[] = [
    `From: ${fromHeader}`,
    `To: ${normalizedToList.join(", ")}`,
    `Reply-To: ${resolvedFromEmail}`,
  ];
  if (normalizedCcList.length > 0) headers.push(`Cc: ${normalizedCcList.join(", ")}`);
  headers.push(`Subject: ${safeSubject}`);
  headers.push(`Date: ${new Date().toUTCString()}`);
  headers.push(`Message-ID: ${messageId}`);
  headers.push(`MIME-Version: 1.0`);

  if (hasAttachments) {
    headers.push(`Content-Type: multipart/mixed; boundary="${boundary}"`);
    mimeMessage = headers.join("\r\n") + "\r\n\r\n";
    mimeMessage += `--${boundary}\r\n`;
    mimeMessage += `Content-Type: multipart/alternative; boundary="${alternativeBoundary}"\r\n\r\n`;
    mimeMessage += `--${alternativeBoundary}\r\n`;
    mimeMessage += `Content-Type: text/plain; charset=UTF-8\r\n`;
    mimeMessage += `Content-Transfer-Encoding: base64\r\n\r\n`;
    mimeMessage += chunkBase64(toBase64Utf8(plainTextContent)) + "\r\n\r\n";
    mimeMessage += `--${alternativeBoundary}\r\n`;
    mimeMessage += `Content-Type: text/html; charset=UTF-8\r\n`;
    mimeMessage += `Content-Transfer-Encoding: base64\r\n\r\n`;
    mimeMessage += chunkBase64(toBase64Utf8(safeHtmlContent)) + "\r\n\r\n";
    mimeMessage += `--${alternativeBoundary}--\r\n\r\n`;

    for (const att of attachments) {
      const filename = att.filename || att.name || "attachment";
      let attachmentContent = att.content || "";

      if (att.path && !att.content) {
        try {
          const resp = await fetch(att.path);
          if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
          const arrBuf = await resp.arrayBuffer();
          const bytes = new Uint8Array(arrBuf);
          // Memory-efficient base64 encoding: process in chunks to avoid
          // building a huge intermediate binary string (which doubles memory).
          const CHUNK = 0x8000; // 32KB
          const parts: string[] = [];
          for (let i = 0; i < bytes.length; i += CHUNK) {
            const slice = bytes.subarray(i, Math.min(i + CHUNK, bytes.length));
            // String.fromCharCode.apply is fast and avoids per-char concat.
            parts.push(String.fromCharCode.apply(null, Array.from(slice)));
          }
          attachmentContent = btoa(parts.join(""));
          if (debug) {
            diagnosticLogs.push(`Attachment ${filename}: ${bytes.length} bytes -> ${attachmentContent.length} base64 chars`);
          }
        } catch (e) {
          const message = e instanceof Error ? e.message : String(e);
          console.error(`Failed to fetch attachment ${filename}:`, e);
          diagnosticLogs.push(`WARN: Failed to fetch attachment ${filename}: ${message}`);
          continue;
        }
      }

      mimeMessage += `--${boundary}\r\n`;
      mimeMessage += `Content-Type: application/octet-stream; name="${filename}"\r\n`;
      mimeMessage += `Content-Disposition: attachment; filename="${filename}"\r\n`;
      mimeMessage += `Content-Transfer-Encoding: base64\r\n\r\n`;

      // Build chunked base64 in an array, then join once (avoids O(n²) string concat)
      const lines: string[] = [];
      for (let i = 0; i < attachmentContent.length; i += 76) {
        lines.push(attachmentContent.substring(i, i + 76));
      }
      mimeMessage += lines.join("\r\n") + "\r\n\r\n";
    }
    mimeMessage += `--${boundary}--\r\n`;
  } else {
    headers.push(`Content-Type: multipart/alternative; boundary="${boundary}"`);
    mimeMessage = headers.join("\r\n") + "\r\n\r\n";
    mimeMessage += `--${boundary}\r\n`;
    mimeMessage += `Content-Type: text/plain; charset=UTF-8\r\n`;
    mimeMessage += `Content-Transfer-Encoding: base64\r\n\r\n`;
    mimeMessage += chunkBase64(toBase64Utf8(plainTextContent)) + "\r\n\r\n";
    mimeMessage += `--${boundary}\r\n`;
    mimeMessage += `Content-Type: text/html; charset=UTF-8\r\n`;
    mimeMessage += `Content-Transfer-Encoding: base64\r\n\r\n`;
    mimeMessage += chunkBase64(toBase64Utf8(safeHtmlContent)) + "\r\n\r\n";
    mimeMessage += `--${boundary}--\r\n`;
  }

  let conn: Deno.Conn | Deno.TlsConn;
  try {
    if (debug) {
      diagnosticLogs.push(`Connecting to ${host}:${port} using ${use_ssl ? "implicit SSL/TLS" : "plain SMTP"}`);
    }

    conn = use_ssl
      ? await withTimeout(
          Deno.connectTls({ hostname: host, port: Number(port) }),
          SMTP_CONNECT_TIMEOUT_MS,
          `Timed out connecting securely to SMTP server ${host}:${port}`
        )
      : await withTimeout(
          Deno.connect({ hostname: host, port: Number(port) }),
          SMTP_CONNECT_TIMEOUT_MS,
          `Timed out connecting to SMTP server ${host}:${port}`
        );
  } catch (connErr) {
    const message = connErr instanceof Error ? connErr.message : String(connErr);
    return { success: false, error: `Failed to connect to SMTP server ${host}:${port} — ${message}`, diagnosticLogs };
  }

  const encoder = new TextEncoder();
  const decoder = new TextDecoder();
  let authSecretCommandsRemaining = 0;

  const readResponse = async (c: Deno.Conn | Deno.TlsConn): Promise<string> => {
    const buf = new Uint8Array(4096);
    const n = await withTimeout(
      c.read(buf),
      SMTP_COMMAND_TIMEOUT_MS,
      `Timed out waiting for SMTP response from ${host}:${port}`
    );

    if (n === null) {
      throw new Error("SMTP server closed the connection unexpectedly.");
    }

    const response = decoder.decode(buf.subarray(0, n));
    if (debug) diagnosticLogs.push(`S: ${response.trim()}`);
    return response;
  };

  const sendCommand = async (c: Deno.Conn | Deno.TlsConn, command: string): Promise<string> => {
    if (debug) {
      let logCmd = command.trim();

      if (command.startsWith("AUTH LOGIN")) {
        logCmd = "AUTH LOGIN ***";
        authSecretCommandsRemaining = 2;
      } else if (authSecretCommandsRemaining > 0) {
        logCmd = "***";
        authSecretCommandsRemaining -= 1;
      }

      diagnosticLogs.push(`C: ${logCmd}`);
    }

    await withTimeout(
      c.write(encoder.encode(command + "\r\n")),
      SMTP_COMMAND_TIMEOUT_MS,
      `Timed out sending SMTP command to ${host}:${port}`
    );

    return await readResponse(c);
  };

  try {
    await readResponse(conn);
    const ehloResp = await sendCommand(conn, "EHLO localhost");

    let activeConn: Deno.Conn | Deno.TlsConn = conn;

    if (!use_ssl && use_tls && ehloResp.includes("STARTTLS")) {
      const starttlsResp = await sendCommand(conn, "STARTTLS");
      if (starttlsResp.startsWith("220")) {
        activeConn = await withTimeout(
          Deno.startTls(conn as Deno.TcpConn, { hostname: host }),
          SMTP_COMMAND_TIMEOUT_MS,
          `Timed out upgrading SMTP connection with STARTTLS for ${host}:${port}`
        );
        await sendCommand(activeConn, "EHLO localhost");
      } else {
        // STARTTLS temporarily unavailable — retry once after a short delay
        if (debug) diagnosticLogs.push(`STARTTLS failed (${starttlsResp.trim()}), retrying in 2s...`);
        await new Promise(r => setTimeout(r, 2000));
        const retryResp = await sendCommand(conn, "STARTTLS");
        if (retryResp.startsWith("220")) {
          activeConn = await withTimeout(
            Deno.startTls(conn as Deno.TcpConn, { hostname: host }),
            SMTP_COMMAND_TIMEOUT_MS,
            `Timed out upgrading SMTP connection with STARTTLS for ${host}:${port}`
          );
          await sendCommand(activeConn, "EHLO localhost");
        } else {
          conn.close();
          return { success: false, error: `SMTP STARTTLS not available: ${retryResp.trim()}. Try again shortly or switch to port 465 (SSL).`, diagnosticLogs };
        }
      }
    }

    await sendCommand(activeConn, "AUTH LOGIN");
    await sendCommand(activeConn, btoa(username));
    const authResp = await sendCommand(activeConn, btoa(password));

    if (!authResp.startsWith("235")) {
      activeConn.close();
      return { success: false, error: `SMTP authentication failed. Check your sender credentials for ${from}.`, diagnosticLogs };
    }

    const mailFromResp = await sendCommand(activeConn, `MAIL FROM:<${resolvedFromEmail}>`);
    if (!mailFromResp.startsWith("250")) {
      activeConn.close();
      return { success: false, error: `SMTP MAIL FROM rejected: ${mailFromResp.trim()}`, diagnosticLogs };
    }

    const allRecipients = [...normalizedToList, ...normalizedCcList, ...normalizedBccList];
    let acceptedRecipients = 0;
    for (const r of allRecipients) {
      const rcptResp = await sendCommand(activeConn, `RCPT TO:<${r.trim()}>`);
      if (!rcptResp.startsWith("250") && !rcptResp.startsWith("251")) {
        diagnosticLogs.push(`WARN: RCPT TO rejected for ${r}: ${rcptResp.trim()}`);
      } else {
        acceptedRecipients += 1;
      }
    }

    if (acceptedRecipients === 0) {
      activeConn.close();
      return {
        success: false,
        error: "SMTP rejected all recipients. Check the recipient address and sender/domain alignment.",
        diagnosticLogs,
      };
    }

    const dataResp = await sendCommand(activeConn, "DATA");
    if (!dataResp.startsWith("354")) {
      activeConn.close();
      return { success: false, error: `SMTP DATA command rejected: ${dataResp.trim()}`, diagnosticLogs };
    }

    // Write message body in chunks to prevent SMTP server idle timeout
    const fullData = dotStuffSmtpData(mimeMessage) + "\r\n.\r\n";
    const CHUNK_SIZE = 4096;
    for (let offset = 0; offset < fullData.length; offset += CHUNK_SIZE) {
      const chunk = fullData.slice(offset, offset + CHUNK_SIZE);
      await withTimeout(
        activeConn.write(encoder.encode(chunk)),
        SMTP_COMMAND_TIMEOUT_MS,
        `Timed out sending SMTP message body chunk to ${host}:${port}`
      );
    }

    const finalResp = await readResponse(activeConn);
    const smtpResponse = finalResp.trim();
    await sendCommand(activeConn, "QUIT");
    activeConn.close();

    if (!finalResp.startsWith("250")) {
      return { success: false, error: `SMTP server rejected message: ${finalResp.trim()}`, diagnosticLogs };
    }

    return { success: true, diagnosticLogs, smtpResponse };
  } catch (smtpErr) {
    try { conn.close(); } catch (_) {}
    const message = smtpErr instanceof Error ? smtpErr.message : String(smtpErr);
    return { success: false, error: `SMTP error: ${message}`, diagnosticLogs };
  }
}

Deno.serve(async (req) => {
  if (req.method === "OPTIONS") {
    return new Response(null, { headers: corsHeaders });
  }

  try {
    const payload = await req.json();
    console.log("[send-smtp-email] Request received, action:", payload.action || "send", "sender_id:", payload.sender_id || "none");
    const supabaseUrl = Deno.env.get("SUPABASE_URL")!;
    const serviceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!;
    const adminClient = createClient(supabaseUrl, serviceKey, {
      auth: { autoRefreshToken: false, persistSession: false },
    });

    // === List Senders ===
    if (payload.action === "list_senders") {
      const auth = await getAuthorizedCaller(req);
      if (auth.error) return auth.error;

      const { data: senders, error } = await adminClient
        .from("email_senders")
        .select("id, sender_name, email_address, smtp_username, is_default, updated_at, verified")
        .eq("is_active", true)
        .order("is_default", { ascending: false })
        .order("updated_at", { ascending: false });

      if (error) {
        return jsonResponse({ success: false, error: (error as Error).message }, 500);
      }

      const latestSenderByKey = new Map<string, any>();
      for (const sender of (senders ?? []).sort((a, b) => new Date(b.updated_at ?? 0).getTime() - new Date(a.updated_at ?? 0).getTime())) {
        const key = buildSenderKey(sender);
        if (!latestSenderByKey.has(key)) {
          latestSenderByKey.set(key, sender);
        }
      }

      const dedupedSenders = Array.from(latestSenderByKey.values()).sort(sortSendersForDisplay);

      return jsonResponse({ success: true, senders: dedupedSenders });
    }

    if (payload.action === "send_direct_message_notification") {
      const auth = await getAuthenticatedCaller(req);
      if (auth.error) return auth.error;

      const recipientIds = Array.isArray(payload.recipient_ids)
        ? payload.recipient_ids.filter((id: unknown) => typeof id === "string" && id.trim())
        : [];
      const message = String(payload.message ?? "").trim();
      const senderName = String(payload.sender_name ?? "Someone").trim() || "Someone";

      if (recipientIds.length === 0 || !message) {
        return jsonResponse({ success: false, error: "Missing required fields: recipient_ids, message" }, 400);
      }

      const { data: profiles, error: profileError } = await adminClient
        .from("profiles")
        .select("user_id, full_name, email, preferred_notification_email")
        .in("user_id", recipientIds);

      if (profileError) return jsonResponse({ success: false, error: profileError.message }, 500);

      const recipients = (profiles ?? [])
        .map((profile: any) => ({
          email: String(profile.preferred_notification_email || profile.email || "").trim(),
          name: String(profile.full_name || "there").trim(),
        }))
        .filter((recipient) => /.+@.+\..+/.test(recipient.email));

      if (recipients.length === 0) {
        return jsonResponse({ success: true, sent: 0, skipped: recipientIds.length, reason: "No recipient email addresses found" });
      }

      const { data: defaultSender, error: senderError } = await adminClient
        .from("email_senders")
        .select(senderSelectFields)
        .eq("is_active", true)
        .eq("is_default", true)
        .order("updated_at", { ascending: false })
        .limit(1)
        .maybeSingle();

      if (senderError || !defaultSender) {
        return jsonResponse({ success: false, error: "No default SMTP sender configured" }, 404);
      }

      const sender = mapSenderRowToConfig(await resolveLatestSenderVariant(adminClient, defaultSender));
      const preview = message.replace(/\s+/g, " ").slice(0, 600);
      const subject = `New message from ${senderName}`;
      let sent = 0;
      const failed: { email: string; error: string }[] = [];

      for (const recipient of recipients) {
        const htmlContent = ensureHtmlDocument(`
          <div style="font-family:Arial,sans-serif;max-width:640px;margin:0 auto;padding:24px;color:#172033;line-height:1.5;">
            <h2 style="margin:0 0 16px;color:#1e3a8a;font-size:20px;">New message from ${escapeHtml(senderName)}</h2>
            <p style="margin:0 0 14px;">Hi ${escapeHtml(recipient.name)},</p>
            <p style="margin:0 0 16px;">You received a new message in Avria Community Management.</p>
            <div style="background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;padding:16px;margin:18px 0;white-space:pre-wrap;">${escapeHtml(preview)}</div>
            <p style="margin:22px 0;"><a href="https://avria.cloud/dashboard/messages" style="background:#1e3a8a;color:#ffffff;padding:12px 18px;text-decoration:none;border-radius:6px;display:inline-block;font-weight:600;">Open messages</a></p>
            <p style="font-size:12px;color:#64748b;margin-top:24px;">Please sign in to reply.</p>
          </div>
        `);

        const result = await sendViaSMTP(sender, [recipient.email], [], [], subject, htmlContent, [], false);
        const latestServerResponse = result.smtpResponse
          ? `S: ${result.smtpResponse}`
          : [...result.diagnosticLogs].reverse().find((entry) => entry.startsWith("S: ")) ?? null;

        try {
          await adminClient.from("email_history").insert({
            user_id: auth.callerId,
            sender_email: sender.from,
            recipient_email: recipient.email,
            subject,
            body_text: htmlContent,
            sent_at: new Date().toISOString(),
            status: result.success ? "accepted" : "failed",
            feature_type: "direct_message_notification",
            email_headers: result.success ? { smtp_response: latestServerResponse } : { error: result.error },
          });
        } catch (logErr) {
          console.error("Failed to log direct message notification email:", logErr);
        }

        if (result.success) sent += 1;
        else failed.push({ email: recipient.email, error: result.error || "SMTP send failed" });
      }

      return jsonResponse({ success: failed.length === 0, sent, failed });
    }

    // === Send Email ===
    const { recipient, cc, bcc, subject, body, html, attachments, debug } = payload;
    if (!recipient || !subject) {
      return jsonResponse({ success: false, error: "Missing required fields: recipient, subject" }, 400);
    }

    const resolvedSender: any = await resolveSender(payload, adminClient, req);
    if (resolvedSender.error) return resolvedSender.error;

    const sender = resolvedSender.sender as SenderConfig;
    console.log("[send-smtp-email] Resolved sender:", JSON.stringify({
      host: sender.host,
      port: sender.port,
      username: sender.username,
      from: sender.from,
      fromEmail: sender.fromEmail,
      envelopeFrom: sender.envelopeFrom,
      use_ssl: sender.use_ssl,
      use_tls: sender.use_tls,
      hasPassword: !!sender.password,
      passwordLength: sender.password?.length ?? 0,
    }));

    const toList = Array.isArray(recipient) ? recipient : [recipient];
    const ccList = Array.isArray(cc) ? cc.filter(Boolean) : [];
    const bccList = Array.isArray(bcc) ? bcc.filter(Boolean) : [];
    let htmlContent = html || body || "";

    // Append sender signature if configured
    if (sender.signature_html) {
      const sigBlock = `<br/><div style="margin-top:16px;border-top:1px solid #e0e0e0;padding-top:12px">${sender.signature_html}</div>`;
      if (htmlContent.includes("</body>")) {
        htmlContent = htmlContent.replace("</body>", `${sigBlock}</body>`);
      } else {
        htmlContent += sigBlock;
      }
    }

    // Inject a 1x1 tracking pixel so opens get recorded into email_history.
    const trackingId = crypto.randomUUID();
    const pixelUrl = `${getPublicFunctionBaseUrl()}/functions/v1/track-email-open?tid=${trackingId}`;
    const pixelTag = `<img src="${pixelUrl}" width="1" height="1" alt="" style="display:none!important;border:0;outline:none;text-decoration:none;width:1px;height:1px;opacity:0;overflow:hidden;" />`;
    if (htmlContent.includes("</body>")) {
      htmlContent = htmlContent.replace("</body>", `${pixelTag}</body>`);
    } else {
      htmlContent += pixelTag;
    }

    const formattedAttachments = Array.isArray(attachments) ? attachments : [];

    const result = await sendViaSMTP(
      sender,
      toList,
      ccList,
      bccList,
      subject,
      htmlContent,
      formattedAttachments,
      debug ?? false
    );

    console.log("[send-smtp-email] SMTP result:", JSON.stringify({ success: result.success, error: result.error, smtpResponse: result.smtpResponse }));

    const latestServerResponse = result.smtpResponse
      ? `S: ${result.smtpResponse}`
      : [...result.diagnosticLogs].reverse().find((entry) => entry.startsWith("S: ")) ?? null;
    const mailStatus = result.success ? "accepted" : "failed";

    // Log to email_history with accurate status
    let historyRecorded = false;
    let historyError: string | undefined;
    try {
      const userId = resolvedSender.callerId ?? payload.fallback_user_id;
      if (userId) {
        const { error: insertHistoryError } = await adminClient.from("email_history").insert({
          user_id: userId,
          sender_email: sender.from,
          recipient_email: toList.join(", "),
          subject,
          body_text: htmlContent,
          sent_at: new Date().toISOString(),
          status: mailStatus,
          feature_type: payload.feature_type || "smtp_email",
          tracking_id: trackingId,
          email_headers: result.success
            ? { smtp_response: latestServerResponse }
            : { error: result.error, diagnostic_logs: debug ? result.diagnosticLogs : undefined },
        });

        if (insertHistoryError) {
          historyError = insertHistoryError.message;
          console.error("Failed to log email history:", insertHistoryError);
        } else {
          historyRecorded = true;
        }
      }
    } catch (logErr) {
      historyError = logErr instanceof Error ? logErr.message : String(logErr);
      console.error("Failed to log email history:", logErr);
    }

    if (!result.success) {
      return jsonResponse({
        success: false,
        error: result.error,
        status: mailStatus,
        diagnostic_logs: debug ? result.diagnosticLogs : undefined,
      }, 500);
    }

    return jsonResponse({
      success: true,
      status: mailStatus,
      history_recorded: historyRecorded,
      history_error: historyError,
      smtp_response: latestServerResponse,
      diagnostic_logs: debug ? result.diagnosticLogs : undefined,
    });
  } catch (error) {
    console.error("send-smtp-email error:", error);
    return jsonResponse({ success: false, error: (error as Error).message }, 500);
  }
});
