/**
 * Appointment Types Reorder API
 *
 * PATCH /api/dashboard/appointment-types/reorder
 *   Bulk-updates the sortOrder of multiple appointment types in a single
 *   transaction.  The frontend sends the full new order after a drag/swap.
 *
 * Request body:
 *   { order: [{ id: string, sortOrder: number }] }
 *
 * Response:
 *   { success: true }
 */

import { NextRequest, NextResponse } from "next/server";
import { auth } from "@/lib/auth";
import { prisma } from "@/lib/db";
import { appointmentTypesAdapter } from "@/lib/adapters/appointment-types";
import { getAuthenticatedUser } from "@/lib/utils/auth-helpers.util";
import { logger } from "@/lib/logger";
import { withCSRF } from "@/lib/csrf";
import { withRateLimit, rateLimiters } from "@/lib/rate-limiter";

const scopedLogger = logger.scope("AppointmentTypesReorderAPI");

export const dynamic = "force-dynamic";

async function patchHandler(request: NextRequest): Promise<NextResponse> {
  try {
    const user = await getAuthenticatedUser(request, auth);
    if (!user) {
      return NextResponse.json(
        { success: false, error: "Unauthorized" },
        { status: 401 },
      );
    }

    let body: unknown;
    try {
      body = await request.json();
    } catch {
      return NextResponse.json(
        { success: false, error: "Invalid JSON body" },
        { status: 400 },
      );
    }

    const { order } = body as { order?: { id: string; sortOrder: number }[] };

    if (!Array.isArray(order) || order.length === 0) {
      return NextResponse.json(
        { success: false, error: "order must be a non-empty array" },
        { status: 400 },
      );
    }

    // Verify all items belong to this user's organisation
    const org = await prisma.organizations.findFirst({
      where: { ownerId: user.userId },
      select: { id: true },
    });

    if (!org) {
      return NextResponse.json(
        { success: false, error: "Organization not found" },
        { status: 404 },
      );
    }

    const ids = order.map((item) => item.id);
    const existingTypes = await appointmentTypesAdapter.findMany({
      where: { id: { in: ids }, organizationId: org.id },
      select: { id: true },
    });

    if (existingTypes.length !== ids.length) {
      return NextResponse.json(
        {
          success: false,
          error: "One or more types not found or access denied",
        },
        { status: 403 },
      );
    }

    // Run all updates in a single transaction
    await prisma.$transaction(
      order.map((item) =>
        prisma.appointment_types.update({
          where: { id: item.id },
          data: { sortOrder: item.sortOrder },
        }),
      ),
    );

    scopedLogger.info("Appointment types reordered", {
      userId: user.userId,
      organizationId: org.id,
      count: order.length,
    });

    return NextResponse.json({ success: true });
  } catch (error) {
    scopedLogger.error("Failed to reorder appointment types", error);
    return NextResponse.json(
      { success: false, error: "Internal server error" },
      { status: 500 },
    );
  }
}

export const PATCH = withRateLimit(
  withCSRF(patchHandler),
  rateLimiters.authGeneral,
);
