import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/db";
import { sendMail } from "@/lib/smtp";
import { saveAttachment } from "@/lib/storage";

const MAX_ATTACHMENT_BYTES = 10 * 1024 * 1024;
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

function parseRecipients(raw: string): string[] {
  const list = raw
    .split(/[,;\n]/)
    .map((s) => s.trim())
    .filter(Boolean);
  // Dedupe case-insensitively so "grace@x.com" typed twice (or with
  // different casing) doesn't send and log the same email twice.
  const seen = new Set<string>();
  return list.filter((email) => {
    const key = email.toLowerCase();
    if (seen.has(key)) return false;
    seen.add(key);
    return true;
  });
}

export async function POST(req: NextRequest) {
  const form = await req.formData();
  const recipientsRaw = String(form.get("recipients") || "");
  const subject = String(form.get("subject") || "");
  const bodyText = String(form.get("body") || "");
  const file = form.get("attachment") as File | null;

  const recipients = parseRecipients(recipientsRaw);
  const invalid = recipients.filter((r) => !EMAIL_RE.test(r));

  if (recipients.length === 0) {
    return NextResponse.json({ error: "At least one recipient is required" }, { status: 400 });
  }
  if (invalid.length > 0) {
    return NextResponse.json(
      { error: `These don't look like valid email addresses: ${invalid.join(", ")}` },
      { status: 400 }
    );
  }
  if (!subject.trim() || !bodyText.trim()) {
    return NextResponse.json({ error: "Subject and message are required" }, { status: 400 });
  }

  let attachmentBuffer: Buffer | undefined;
  let attachmentMeta: { filename: string; contentType: string } | undefined;

  if (file && file.size > 0) {
    if (file.size > MAX_ATTACHMENT_BYTES) {
      return NextResponse.json({ error: "Attachment exceeds 10MB limit" }, { status: 400 });
    }
    attachmentBuffer = Buffer.from(await file.arrayBuffer());
    attachmentMeta = { filename: file.name, contentType: file.type };
  }

  const results = [];

  for (const email of recipients) {
    try {
      await sendMail({
        to: email,
        subject,
        text: bodyText,
        attachments: attachmentBuffer
          ? [{ filename: attachmentMeta!.filename, content: attachmentBuffer, contentType: attachmentMeta!.contentType }]
          : undefined,
      });
    } catch (err: unknown) {
      const message = err instanceof Error ? err.message : "Unknown send error";
      results.push({ email, sent: false, error: message });
      continue;
    }

    // Find or create the contact this recipient belongs to. Emails are
    // matched case-insensitively (normalized to lowercase) so "Grace@x.com"
    // and "grace@x.com" are always treated as the same person — this has to
    // match the normalization the IMAP poller uses, or the same person could
    // end up as two separate contacts.
    const normalizedEmail = email.toLowerCase();
    let contact = await prisma.contact.findUnique({ where: { email: normalizedEmail } });
    if (!contact) {
      contact = await prisma.contact.create({
        data: { email: normalizedEmail, status: "ACTIVE", source: "Manual outbound (Compose)" },
      });
    } else if (contact.status !== "ACTIVE") {
      // Deliberately emailing someone is a decision to engage with them —
      // reflect that instead of leaving them stuck in Unassigned/Archived
      // while an actual conversation is happening.
      contact = await prisma.contact.update({ where: { id: contact.id }, data: { status: "ACTIVE" } });
    }

    const message = await prisma.emailMessage.create({
      data: {
        contactId: contact.id,
        direction: "OUTBOUND",
        subject,
        bodyText,
        fromAddress: process.env.FROM_EMAIL || "info@midhubsolutions.com",
        toAddress: email,
      },
    });

    if (attachmentBuffer && attachmentMeta) {
      const stored = await saveAttachment(contact.id, message.id, attachmentMeta.filename, attachmentBuffer);
      await prisma.attachment.create({
        data: {
          messageId: message.id,
          filename: attachmentMeta.filename,
          storedPath: stored.relativePath,
          contentType: attachmentMeta.contentType,
          sizeBytes: attachmentBuffer.length,
        },
      });
    }

    await prisma.contact.update({ where: { id: contact.id }, data: { updatedAt: new Date() } });

    results.push({ email, sent: true, contactId: contact.id });
  }

  const failures = results.filter((r) => !r.sent);
  return NextResponse.json(
    { results, allSent: failures.length === 0 },
    { status: failures.length === 0 ? 201 : 207 }
  );
}
