import { Router } from "express";
import jwt from "jsonwebtoken";
import { env } from "../lib/env";
import {
  buildAuthorizeUrl,
  exchangeCodeForTokens,
  fetchGraphProfile,
  getMicrosoftAppConfig,
} from "../lib/microsoftGraph";
import { prisma } from "../lib/prisma";
import { encryptSecret } from "../lib/tokenCrypto";
import { HttpError } from "../middleware/errorHandler";
import { requireAuth } from "../middleware/requireAuth";

export const mailRouter = Router();

const MAIL_LISTS = ["Flagged", "Needs Reply", "Other"];

async function createMailBoard(userId: string, email: string) {
  const membership = await prisma.workspaceMember.findFirst({
    where: { userId },
    orderBy: { joinedAt: "asc" },
  });
  if (!membership) {
    throw new HttpError(400, "Join or create a workspace before connecting a mailbox");
  }

  const board = await prisma.board.create({
    data: {
      workspaceId: membership.workspaceId,
      name: `Mail — ${email}`,
      visibility: "PRIVATE",
      backgroundType: "GRADIENT",
      backgroundValue: "gradient-ocean",
      members: { create: { userId, role: "ADMIN" } },
      lists: { create: MAIL_LISTS.map((name, i) => ({ name, position: (i + 1) * 1000 })) },
    },
  });
  return board;
}

mailRouter.get("/status", requireAuth, async (req, res, next) => {
  try {
    const account = await prisma.mailAccount.findUnique({ where: { userId: req.userId! } });
    if (!account) {
      res.json({ connected: false });
      return;
    }
    res.json({
      connected: true,
      email: account.email,
      boardId: account.boardId,
      lastSyncedAt: account.lastSyncedAt,
      lastSyncError: account.lastSyncError,
    });
  } catch (err) {
    next(err);
  }
});

mailRouter.get("/connect", requireAuth, async (req, res) => {
  const config = await getMicrosoftAppConfig();
  if (!config) {
    res.redirect(
      `${env.CLIENT_URL}/settings/profile?mailError=${encodeURIComponent(
        "Microsoft integration isn't configured yet — ask a system admin to set it up."
      )}`
    );
    return;
  }
  const state = jwt.sign({ userId: req.userId }, env.JWT_SECRET, { expiresIn: "10m" });
  res.redirect(buildAuthorizeUrl(config, state));
});

mailRouter.get("/callback", async (req, res) => {
  const redirectWithError = (message: string) =>
    res.redirect(`${env.CLIENT_URL}/settings/profile?mailError=${encodeURIComponent(message)}`);

  try {
    const { code, state, error, error_description } = req.query as Record<string, string>;
    if (error) {
      redirectWithError(error_description || error);
      return;
    }
    if (!code || !state) {
      redirectWithError("Missing authorization code");
      return;
    }

    let userId: string;
    try {
      userId = (jwt.verify(state, env.JWT_SECRET) as { userId: string }).userId;
    } catch {
      redirectWithError("Your connection attempt expired — please try again");
      return;
    }

    const config = await getMicrosoftAppConfig();
    if (!config) {
      redirectWithError("Microsoft integration isn't configured");
      return;
    }

    const tokens = await exchangeCodeForTokens(config, code);
    const profile = await fetchGraphProfile(tokens.access_token);
    const tokenExpiresAt = new Date(Date.now() + tokens.expires_in * 1000);

    const existing = await prisma.mailAccount.findUnique({ where: { userId } });

    if (existing) {
      await prisma.mailAccount.update({
        where: { userId },
        data: {
          email: profile.email,
          accessToken: encryptSecret(tokens.access_token),
          refreshToken: encryptSecret(tokens.refresh_token),
          tokenExpiresAt,
          lastSyncError: null,
        },
      });
    } else {
      const board = await createMailBoard(userId, profile.email);
      await prisma.mailAccount.create({
        data: {
          userId,
          boardId: board.id,
          email: profile.email,
          accessToken: encryptSecret(tokens.access_token),
          refreshToken: encryptSecret(tokens.refresh_token),
          tokenExpiresAt,
        },
      });
    }

    res.redirect(`${env.CLIENT_URL}/settings/profile?mail=connected`);
  } catch (err) {
    console.error("[mail] OAuth callback failed:", err);
    redirectWithError("Something went wrong connecting your mailbox");
  }
});

mailRouter.post("/disconnect", requireAuth, async (req, res, next) => {
  try {
    await prisma.mailAccount.deleteMany({ where: { userId: req.userId! } });
    res.status(204).send();
  } catch (err) {
    next(err);
  }
});
