import { NextRequest, NextResponse } from "next/server";
import { db, isDatabaseAvailable } from "@/lib/db";
import { ensureDatabaseInitialized } from "@/lib/db/init";
import { projects, receipts } from "@/lib/schema/db";
import { eq, and, inArray } from "drizzle-orm";
import { getCurrentUser } from "@/lib/auth/session";
import { requireCsrf } from "@/lib/auth/csrf";
import { isProActive } from "@/lib/billing/access";
import {
  resolveGuestContext,
  applyGuestCookie,
  type GuestContext,
} from "@/lib/auth/guest";

export const runtime = "nodejs";

async function resolveScope(req: NextRequest): Promise<{
  user: Awaited<ReturnType<typeof getCurrentUser>>;
  userId: string;
  guest: GuestContext | null;
}> {
  const user = await getCurrentUser(req);
  if (user) return { user, userId: user.id, guest: null };

  const guest = resolveGuestContext(req);
  return { user: null, userId: guest.bucket, guest };
}

function isProUser(user: Awaited<ReturnType<typeof getCurrentUser>>): boolean {
  return isProActive(user);
}

/**
 * PATCH /api/receipts/project
 * Bulk-assigns (or clears, with projectId: null) the project a set of the
 * caller's own receipts belong to. Deliberately a separate endpoint from the
 * big POST /api/receipts batch-upsert so a plain "edit and save" receipt
 * roundtrip can never accidentally clear a receipt's project assignment.
 */
export async function PATCH(req: NextRequest) {
  try {
    const csrfBlocked = requireCsrf(req);
    if (csrfBlocked) return csrfBlocked;

    const dbAvailable = await isDatabaseAvailable();
    if (!dbAvailable) {
      return NextResponse.json({ error: "Database unavailable." }, { status: 503 });
    }

    await ensureDatabaseInitialized();
    const scope = await resolveScope(req);

    if (!isProUser(scope.user)) {
      return NextResponse.json({ error: "pro_required" }, { status: 402 });
    }

    const body = await req.json().catch(() => null);
    const ids = Array.isArray(body?.ids)
      ? body.ids.filter((id: unknown): id is string => typeof id === "string" && id.length > 0)
      : [];
    const projectId = body?.projectId === null ? null : body?.projectId;

    if (ids.length === 0) {
      return NextResponse.json({ error: "No receipt ids provided." }, { status: 400 });
    }
    if (projectId !== null && typeof projectId !== "string") {
      return NextResponse.json({ error: "projectId must be a string or null." }, { status: 400 });
    }

    if (projectId !== null) {
      const owned = await db
        .select({ id: projects.id })
        .from(projects)
        .where(and(eq(projects.id, projectId), eq(projects.userId, scope.userId)))
        .limit(1);
      if (owned.length === 0) {
        return NextResponse.json({ error: "Project not found." }, { status: 404 });
      }
    }

    const result = await db
      .update(receipts)
      .set({ projectId, updatedAt: new Date() })
      .where(and(eq(receipts.userId, scope.userId), inArray(receipts.id, ids)))
      .returning({ id: receipts.id });

    return applyGuestCookie(
      NextResponse.json({ success: true, updatedCount: result.length }),
      scope.guest
    );
  } catch (error: any) {
    console.error("PATCH /api/receipts/project error:", error);
    return NextResponse.json({ error: "Failed to assign receipts." }, { status: 500 });
  }
}
