import { NextResponse } from "next/server";
import { auth, clerkClient } from "@clerk/nextjs/server";

/**
 * POST /api/invitations
 *
 * Create a Clerk-managed invitation and store role/gym context in publicMetadata.
 * This endpoint does not implement invitation acceptance; Clerk’s acceptance link flow and webhooks will handle that.
 *
 * Body: {
 *   inviteeEmail: string,
 *   roleAssigned: 'trainer' | 'client' | 'admin'
 * }
 *
 * Rules:
 * - admin: can invite trainer or client; the gymId is taken from inviter's publicMetadata or user record.
 * - trainer: can invite client; the gymId is taken from inviter's publicMetadata or user record.
 * - superAdmin: can invite admin; requires `gymId` in body, or falls back to inviter's `gymId` if present.
 *
 * Returns Clerk invitation payload.
 */
export async function POST(req: Request) {
  try {
    const { userId } = await auth();
    if (!userId) {
      return new NextResponse("Unauthorized", { status: 401 });
    }

    const body = await req.json().catch(() => null);
    if (!body || typeof body !== "object") {
      return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 });
    }

    const inviteeEmail = String(body.inviteeEmail ?? "")
      .trim()
      .toLowerCase();
    const roleAssigned = String(body.roleAssigned ?? "").trim() as
      | "trainer"
      | "client"
      | "admin";
    let requestedGymId: string | null = body.gymId ? String(body.gymId) : null;

    if (!inviteeEmail || !roleAssigned) {
      return NextResponse.json(
        { error: "inviteeEmail and roleAssigned are required" },
        { status: 400 },
      );
    }

    // Fetch inviter user from Clerk
    const client = await clerkClient();
    const inviter = await client.users.getUser(userId);
    const inviterRole =
      (inviter.publicMetadata?.role as
        | "superAdmin"
        | "admin"
        | "trainer"
        | "client"
        | "generalUser") ?? "client";
    const inviterGymId =
      (inviter.publicMetadata?.gymId as string | undefined) ?? undefined;

    // Enforce role-based rules and resolve target gymId for the invitation
    let gymIdForInvite: string | null = null;
    switch (inviterRole) {
      case "admin": {
        if (roleAssigned !== "trainer" && roleAssigned !== "client") {
          return NextResponse.json(
            { error: "Admin can only invite trainer or client" },
            { status: 403 },
          );
        }
        if (!inviterGymId) {
          return NextResponse.json(
            { error: "Inviter admin must be assigned to a gym" },
            { status: 400 },
          );
        }
        gymIdForInvite = inviterGymId;
        break;
      }
      case "trainer": {
        if (roleAssigned !== "client") {
          return NextResponse.json(
            { error: "Trainer can only invite client" },
            { status: 403 },
          );
        }
        if (!inviterGymId) {
          return NextResponse.json(
            { error: "Inviter trainer must be assigned to a gym" },
            { status: 400 },
          );
        }
        gymIdForInvite = inviterGymId;
        break;
      }
      case "superAdmin": {
        if (
          roleAssigned !== "admin" &&
          roleAssigned !== "trainer" &&
          roleAssigned !== "client"
        ) {
          return NextResponse.json(
            { error: "Invalid roleAssigned for SuperAdmin" },
            { status: 400 },
          );
        }
        // Prefer explicitly provided gymId, otherwise fall back to inviter's gymId if present
        gymIdForInvite = requestedGymId || inviterGymId || null;
        if (!gymIdForInvite) {
          return NextResponse.json(
            { error: "gymId is required for SuperAdmin when inviting" },
            { status: 400 },
          );
        }
        break;
      }
      default: {
        return NextResponse.json(
          { error: "Inviter role not permitted to create invitations" },
          { status: 403 },
        );
      }
    }

    // Create Clerk invitation with metadata needed by webhook to assign role & gym
    // reuse existing Clerk client instance
    const invitation = await client.invitations.createInvitation({
      emailAddress: inviteeEmail,
      publicMetadata: {
        roleAssigned,
        gymId: gymIdForInvite,
        inviterUserId: inviter.id,
      },
    });

    return NextResponse.json(invitation, { status: 201 });
  } catch (error: any) {
    // Surface Clerk errors where possible
    const message =
      error?.errors?.[0]?.message ||
      error?.message ||
      "Failed to create invitation";
    console.error("POST /api/invitations error:", error);
    return NextResponse.json({ error: message }, { status: 500 });
  }
}
