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

/**
 * POST /api/admin/set-user-metadata
 *
 * Sets Clerk publicMetadata.role and publicMetadata.gymId for a target user.
 *
 * Authorization:
 * - Caller must be an admin or superAdmin (based on their Clerk publicMetadata.role).
 *
 * Request body:
 * {
 *   "targetUserId": string,                  // Clerk user ID of the target
 *   "role": "superAdmin" | "admin" | "trainer" | "client" | "generalUser", // optional
 *   "gymId": string | null                   // optional; null clears gym assignment
 * }
 *
 * Behavior:
 * - If "role" is provided, update the target user's publicMetadata.role.
 * - If "gymId" is provided (including null), update publicMetadata.gymId.
 * - Validates inputs and permissions.
 *
 * Response:
 * - 200 with updated minimal user data
 * - 400/401/403/404/500 on errors
 */
export async function POST(req: Request) {
  try {
    // Authenticate the requester
    const { userId } = await auth();
    if (!userId) {
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
    }

    const client = await clerkClient();

    // Fetch requester from Clerk to verify permissions
    const requester = await client.users.getUser(userId);
    const requesterRole =
      (requester.publicMetadata?.role as
        | "superAdmin"
        | "admin"
        | "trainer"
        | "client"
        | "generalUser") ?? "client";

    // Only admin or superAdmin can set metadata
    if (requesterRole !== "admin" && requesterRole !== "superAdmin") {
      return NextResponse.json(
        { error: "Forbidden: admin or superAdmin access required" },
        { status: 403 }
      );
    }

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

    const targetUserId = typeof body.targetUserId === "string" ? body.targetUserId : null;
    const role = body.role as
      | "superAdmin"
      | "admin"
      | "trainer"
      | "client"
      | "generalUser"
      | undefined;
    const gymId =
      body.gymId === null
        ? null
        : typeof body.gymId === "string"
        ? body.gymId
        : undefined;

    if (!targetUserId) {
      return NextResponse.json(
        { error: "Invalid or missing targetUserId" },
        { status: 400 }
      );
    }

    // Validate role if provided
    const allowedRoles = ["superAdmin", "admin", "trainer", "client", "generalUser"] as const;
    if (role && !allowedRoles.includes(role)) {
      return NextResponse.json(
        { error: "Invalid role. Must be one of superAdmin, admin, trainer, client, generalUser" },
        { status: 400 }
      );
    }

    // Prevent non-superAdmin from assigning superAdmin
    if (role === "superAdmin" && requesterRole !== "superAdmin") {
      return NextResponse.json(
        { error: "Only superAdmin can assign superAdmin role" },
        { status: 403 }
      );
    }

    // Fetch target user to ensure they exist
    let targetUser;
    try {
      targetUser = await client.users.getUser(targetUserId);
    } catch {
      return NextResponse.json({ error: "Target user not found" }, { status: 404 });
    }

    // Construct new metadata by merging with existing
    const newPublicMetadata: Record<string, unknown> = {
      ...(targetUser.publicMetadata || {}),
    };

    if (role !== undefined) {
      newPublicMetadata.role = role;
    }
    if (gymId !== undefined) {
      newPublicMetadata.gymId = gymId;
    }

    // Ensure at least one field to update
    if (role === undefined && gymId === undefined) {
      return NextResponse.json(
        { error: "Provide at least one of 'role' or 'gymId' to update" },
        { status: 400 }
      );
    }

    // Perform update on Clerk
    const updatedUser = await client.users.updateUser(targetUserId, {
      publicMetadata: newPublicMetadata,
    });

    // Construct response payload
    const primaryEmail =
      updatedUser.emailAddresses?.find(
        (e) => e.id === updatedUser.primaryEmailAddressId
      )?.emailAddress || updatedUser.emailAddresses?.[0]?.emailAddress || null;

    return NextResponse.json(
      {
        success: true,
        message: "User metadata updated",
        user: {
          id: updatedUser.id,
          email: primaryEmail,
          firstName: updatedUser.firstName,
          lastName: updatedUser.lastName,
          role: updatedUser.publicMetadata?.role ?? null,
          gymId: updatedUser.publicMetadata?.gymId ?? null,
        },
      },
      { status: 200 }
    );
  } catch (error: any) {
    const message =
      error?.errors?.[0]?.message ||
      error?.message ||
      "Internal server error";
    console.error("Error setting user metadata:", error);
    return NextResponse.json({ error: message }, { status: 500 });
  }
}
