import { NextResponse } from "next/server";
import { getServerSession } from "next-auth";
import { DepartmentKey, RoleKey } from "@prisma/client";
import { authOptions } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
import { generateInvitationToken, getInviteExpiresAt } from "@/lib/invitations";
import { sendInvitationEmail } from "@/lib/email";
import { canInviteUsers, getAssignableRoles } from "@/lib/roles";

type InvitationRequestBody = {
  inviteeName?: string;
  email?: string;
  department?: string;
  departmentRole?: string;
  roleKey?: string;
};

export async function POST(request: Request) {
  const session = await getServerSession(authOptions);
  if (!session?.user) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const body = (await request.json()) as InvitationRequestBody;
  const inviteeName = body.inviteeName?.trim() ?? "";
  const email = body.email?.toLowerCase().trim();
  const departmentRole = body.departmentRole?.trim() ?? "";
  const sessionDepartment = session.user.department ?? null;

  if (!canInviteUsers(session.user.role)) {
    return NextResponse.json({ error: "Only owners or leaders can invite team members." }, { status: 403 });
  }

  if (inviteeName.length < 2 || inviteeName.length > 100) {
    return NextResponse.json({ error: "Invalid inviteeName." }, { status: 400 });
  }

  if (!email || !email.includes("@") || email.length > 255) {
    return NextResponse.json({ error: "Invalid email." }, { status: 400 });
  }

  if (!body.department || !Object.values(DepartmentKey).includes(body.department as DepartmentKey)) {
    return NextResponse.json({ error: "Invalid department." }, { status: 400 });
  }

  if (departmentRole.length < 2 || departmentRole.length > 80) {
    return NextResponse.json({ error: "Invalid departmentRole." }, { status: 400 });
  }

  if (!body.roleKey || !Object.values(RoleKey).includes(body.roleKey as RoleKey)) {
    return NextResponse.json({ error: "Invalid roleKey." }, { status: 400 });
  }

  const department = body.department as DepartmentKey;
  const roleKey = body.roleKey as RoleKey;
  const allowedRoleKeys = getAssignableRoles(session.user.role);

  if (!allowedRoleKeys.includes(roleKey)) {
    return NextResponse.json(
      { error: `Role ${session.user.role} can invite only: ${allowedRoleKeys.join(", ")}` },
      { status: 403 }
    );
  }

  if (session.user.role === "leader") {
    if (!sessionDepartment) {
      return NextResponse.json({ error: "Leader account has no department assigned." }, { status: 403 });
    }

    if (department !== sessionDepartment) {
      return NextResponse.json({ error: "Leaders can invite only members of their own department." }, { status: 403 });
    }
  }

  const role = await prisma.role.findUnique({ where: { key: roleKey } });
  if (!role) {
    return NextResponse.json({ error: "Role not found in DB. Run seed first." }, { status: 400 });
  }

  const { token, tokenHash } = generateInvitationToken();
  const expiresAt = getInviteExpiresAt();

  const invitation = await prisma.invitation.create({
    data: {
      inviteeName,
      email,
      roleKey,
      department,
      departmentRole,
      tokenHash,
      expiresAt,
      invitedById: session.user.id,
    },
  });

  try {
    await sendInvitationEmail({
      toEmail: email,
      token,
      inviteeName,
      roleKey,
      department,
      departmentRole,
      expiresAt,
      invitedByName: session.user.name,
    });
  } catch (error) {
    return NextResponse.json(
      {
        error: error instanceof Error ? error.message : "Failed to send invitation email.",
        invitationId: invitation.id,
      },
      { status: 500 }
    );
  }

  return NextResponse.json({
    ok: true,
    invitationId: invitation.id,
    inviteeName,
    email,
    department,
    departmentRole,
    roleKey,
    expiresAt: expiresAt.toISOString(),
  });
}
