import { NextResponse } from "next/server";
import bcrypt from "bcryptjs";
import { prisma } from "@/lib/prisma";
import { hashInvitationToken } from "@/lib/invitations";

type AcceptInvitationBody = {
  token?: string;
  email?: string;
  name?: string;
  password?: string;
};

export async function POST(request: Request) {
  const body = (await request.json()) as AcceptInvitationBody;
  const token = body.token?.trim() ?? "";
  const email = body.email?.toLowerCase().trim() ?? "";
  const submittedName = body.name?.trim() ?? "";
  const password = body.password ?? "";

  if (!token || !email || password.length < 8) {
    return NextResponse.json({ error: "Invalid payload." }, { status: 400 });
  }

  const tokenHash = hashInvitationToken(token);
  const invitation = await prisma.invitation.findFirst({
    where: {
      email,
      tokenHash,
      acceptedAt: null,
      expiresAt: { gt: new Date() },
    },
  });

  if (!invitation) {
    return NextResponse.json({ error: "Invitation is invalid or expired." }, { status: 400 });
  }

  const role = await prisma.role.findUnique({
    where: { key: invitation.roleKey },
  });

  if (!role) {
    return NextResponse.json({ error: "Role not found in DB. Run seed first." }, { status: 400 });
  }

  const name = submittedName || invitation.inviteeName;

  const passwordHash = await bcrypt.hash(password, 12);

  await prisma.$transaction(async (tx) => {
    const user = await tx.user.upsert({
      where: { email },
      update: {
        name,
        passwordHash,
        status: "active",
        emailVerified: new Date(),
        department: invitation.department,
        departmentRole: invitation.departmentRole,
      },
      create: {
        email,
        name,
        passwordHash,
        status: "active",
        emailVerified: new Date(),
        department: invitation.department,
        departmentRole: invitation.departmentRole,
      },
    });

    await tx.userRole.upsert({
      where: {
        userId_roleId: {
          userId: user.id,
          roleId: role.id,
        },
      },
      update: {},
      create: {
        userId: user.id,
        roleId: role.id,
      },
    });

    await tx.userRole.deleteMany({
      where: {
        userId: user.id,
        roleId: {
          not: role.id,
        },
      },
    });

    await tx.invitation.update({
      where: { id: invitation.id },
      data: { acceptedAt: new Date() },
    });
  });

  return NextResponse.json({ ok: true });
}
