import { Router } from "express";
import { google, gmail_v1 } from "googleapis";
import { requireAuth, requireCapability } from "../../middleware/auth";
import { getOwnerGoogleClient, sendGoogleError } from "../../lib/google-user";

export const mailRouter = Router();
mailRouter.use(requireAuth);

function header(headers: gmail_v1.Schema$MessagePartHeader[] | undefined, name: string): string {
  const h = headers?.find((x) => (x.name ?? "").toLowerCase() === name.toLowerCase());
  return h?.value ?? "";
}

function decodeBody(data?: string | null): string {
  return data ? Buffer.from(data, "base64url").toString("utf8") : "";
}

interface Extracted {
  html?: string;
  text?: string;
  attachments: { filename: string; mimeType: string; size: number; attachmentId: string }[];
}

function walkParts(part: gmail_v1.Schema$MessagePart | undefined, acc: Extracted) {
  if (!part) return;
  const mime = part.mimeType ?? "";
  const filename = part.filename ?? "";
  if (filename && part.body?.attachmentId) {
    acc.attachments.push({
      filename,
      mimeType: mime,
      size: part.body.size ?? 0,
      attachmentId: part.body.attachmentId,
    });
  } else if (mime === "text/plain" && part.body?.data && !acc.text) {
    acc.text = decodeBody(part.body.data);
  } else if (mime === "text/html" && part.body?.data && !acc.html) {
    acc.html = decodeBody(part.body.data);
  }
  part.parts?.forEach((p) => walkParts(p, acc));
}

// GET /mail/messages — liste des derniers messages de la boîte de réception.
mailRouter.get("/messages", requireCapability("mail:read"), async (req, res) => {
  try {
    const auth = await getOwnerGoogleClient();
    const gmail = google.gmail({ version: "v1", auth });

    const maxResults = Math.min(Number(req.query.maxResults) || 20, 50);
    const pageToken = req.query.pageToken ? String(req.query.pageToken) : undefined;

    const list = await gmail.users.messages.list({
      userId: "me",
      labelIds: ["INBOX"],
      maxResults,
      pageToken,
    });

    const ids = (list.data.messages ?? []).map((m) => m.id!).filter(Boolean);
    const messages = await Promise.all(
      ids.map(async (id) => {
        const { data } = await gmail.users.messages.get({
          userId: "me",
          id,
          format: "metadata",
          metadataHeaders: ["From", "Subject", "Date"],
        });
        return {
          id: data.id,
          threadId: data.threadId,
          from: header(data.payload?.headers, "From"),
          subject: header(data.payload?.headers, "Subject") || "(sans objet)",
          date: header(data.payload?.headers, "Date"),
          snippet: data.snippet ?? "",
          unread: (data.labelIds ?? []).includes("UNREAD"),
        };
      })
    );

    res.json({ messages, nextPageToken: list.data.nextPageToken ?? null });
  } catch (err) {
    sendGoogleError(res, err, "Gmail");
  }
});

// GET /mail/messages/:id — contenu complet d'un message.
mailRouter.get("/messages/:id", requireCapability("mail:read"), async (req, res) => {
  try {
    const auth = await getOwnerGoogleClient();
    const gmail = google.gmail({ version: "v1", auth });

    const { data } = await gmail.users.messages.get({
      userId: "me",
      id: String(req.params.id),
      format: "full",
    });

    const acc: Extracted = { attachments: [] };
    walkParts(data.payload, acc);
    // Message simple : le corps peut être directement sur le payload.
    if (!acc.text && !acc.html && data.payload?.body?.data) {
      const body = decodeBody(data.payload.body.data);
      if ((data.payload.mimeType ?? "") === "text/html") acc.html = body;
      else acc.text = body;
    }

    res.json({
      id: data.id,
      threadId: data.threadId,
      from: header(data.payload?.headers, "From"),
      to: header(data.payload?.headers, "To"),
      subject: header(data.payload?.headers, "Subject") || "(sans objet)",
      date: header(data.payload?.headers, "Date"),
      unread: (data.labelIds ?? []).includes("UNREAD"),
      bodyHtml: acc.html ?? null,
      bodyText: acc.text ?? null,
      attachments: acc.attachments,
    });
  } catch (err) {
    sendGoogleError(res, err, "Gmail");
  }
});

// Actions (écriture) — admin/super_admin (capacité mail:write).
async function modify(req: import("express").Request, res: import("express").Response, body: gmail_v1.Schema$ModifyMessageRequest) {
  try {
    const auth = await getOwnerGoogleClient();
    const gmail = google.gmail({ version: "v1", auth });
    await gmail.users.messages.modify({ userId: "me", id: String(req.params.id), requestBody: body });
    res.json({ ok: true });
  } catch (err) {
    sendGoogleError(res, err, "Gmail");
  }
}

mailRouter.post("/messages/:id/read", requireCapability("mail:write"), (req, res) =>
  modify(req, res, { removeLabelIds: ["UNREAD"] })
);
mailRouter.post("/messages/:id/unread", requireCapability("mail:write"), (req, res) =>
  modify(req, res, { addLabelIds: ["UNREAD"] })
);
mailRouter.post("/messages/:id/archive", requireCapability("mail:write"), (req, res) =>
  modify(req, res, { removeLabelIds: ["INBOX"] })
);

mailRouter.post("/messages/:id/trash", requireCapability("mail:write"), async (req, res) => {
  try {
    const auth = await getOwnerGoogleClient();
    const gmail = google.gmail({ version: "v1", auth });
    await gmail.users.messages.trash({ userId: "me", id: String(req.params.id) });
    res.json({ ok: true });
  } catch (err) {
    sendGoogleError(res, err, "Gmail");
  }
});
