/**
 * Appointment Types — individual resource endpoints
 *
 * PATCH  /api/dashboard/appointment-types/[id]
 *   Partially updates an existing appointment type.
 *   The owning organisation is verified before the update.
 *
 * DELETE /api/dashboard/appointment-types/[id]
 *   Soft-deletes the type by setting isActive = false.
 *   The frontend (AppointmentTypesManager) only fetches isActive=true records,
 *   so a soft delete is sufficient and preserves referential history.
 */

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 { validateCSRFToken } from "@/lib/csrf";
import { applyRateLimit, rateLimiters } from "@/lib/rate-limiter";

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

export const dynamic = "force-dynamic";

// ---------------------------------------------------------------------------
// Shared helper — resolve org and verify ownership of a given type id
// ---------------------------------------------------------------------------

async function resolveOrgAndType(
  userId: string,
  typeId: string,
): Promise<
  { success: true; orgId: string } | { success: false; response: NextResponse }
> {
  const org = await prisma.organizations.findFirst({
    where: { ownerId: userId },
    select: { id: true },
  });

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

  const existing = await appointmentTypesAdapter.findFirst({
    where: { id: typeId, organizationId: org.id },
    select: { id: true },
  });

  if (!existing) {
    return {
      success: false,
      response: NextResponse.json(
        {
          success: false,
          error: "Appointment type not found or access denied",
        },
        { status: 404 },
      ),
    };
  }

  return { success: true, orgId: org.id };
}

// ---------------------------------------------------------------------------
// PATCH
// ---------------------------------------------------------------------------

export async function PATCH(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> },
) {
  try {
    // Rate limit check
    const rateLimitResponse = await applyRateLimit(
      request,
      rateLimiters.authGeneral,
    );
    if (rateLimitResponse) return rateLimitResponse;

    // CSRF check
    if (!validateCSRFToken(request)) {
      return NextResponse.json(
        { success: false, error: "Invalid or missing CSRF token" },
        { status: 403 },
      );
    }

    const user = await getAuthenticatedUser(request, auth);
    if (!user) {
      return NextResponse.json(
        { success: false, error: "Unauthorized" },
        { status: 401 },
      );
    }

    const { id } = await params;

    const resolved = await resolveOrgAndType(user.userId, id);
    if (!resolved.success) return resolved.response;

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

    const { nameEn, nameAr, duration, price, category, categoryAr, isActive } =
      body as Record<string, unknown>;

    // Build the update payload — only include fields that were explicitly provided
    const data: Record<string, unknown> = {};

    if (nameEn !== undefined) data.nameEn = String(nameEn).trim();
    if (nameAr !== undefined) data.nameAr = String(nameAr).trim();
    if (duration !== undefined) data.duration = Number(duration);
    if (price !== undefined) {
      data.price = price === null ? null : Number(price);
    }
    if (category !== undefined) {
      data.category = category === null ? null : String(category);
    }
    if (categoryAr !== undefined) {
      data.categoryAr = categoryAr === null ? null : String(categoryAr);
    }
    if (isActive !== undefined) data.isActive = Boolean(isActive);

    if (Object.keys(data).length === 0) {
      return NextResponse.json(
        { success: false, error: "No fields to update" },
        { status: 400 },
      );
    }

    const type = await appointmentTypesAdapter.update({
      where: { id },
      data,
    });

    scopedLogger.info("Appointment type updated", {
      userId: user.userId,
      typeId: id,
    });

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

// ---------------------------------------------------------------------------
// DELETE  (soft delete — sets isActive = false)
// ---------------------------------------------------------------------------

export async function DELETE(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> },
) {
  try {
    // Rate limit check
    const rateLimitResponse = await applyRateLimit(
      request,
      rateLimiters.authGeneral,
    );
    if (rateLimitResponse) return rateLimitResponse;

    // CSRF check
    if (!validateCSRFToken(request)) {
      return NextResponse.json(
        { success: false, error: "Invalid or missing CSRF token" },
        { status: 403 },
      );
    }

    const user = await getAuthenticatedUser(request, auth);
    if (!user) {
      return NextResponse.json(
        { success: false, error: "Unauthorized" },
        { status: 401 },
      );
    }

    const { id } = await params;

    const resolved = await resolveOrgAndType(user.userId, id);
    if (!resolved.success) return resolved.response;

    await appointmentTypesAdapter.update({
      where: { id },
      data: { isActive: false },
    });

    scopedLogger.info("Appointment type soft-deleted", {
      userId: user.userId,
      typeId: id,
    });

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