import { and, eq } from 'drizzle-orm';
import { NextResponse } from 'next/server';

import type { AuthContext } from '@/lib/api/helpers';
import { parseBody } from '@/lib/api/route-helpers';
import { db } from '@/lib/db';
import { savedViews } from '@/lib/db/schema';
import { errorResponse, ForbiddenError, NotFoundError } from '@/lib/errors';
import { savedViewsService } from '@/lib/services/saved-views.service';
import { updateSavedViewSchema } from '@/lib/validators/saved-views';

/**
 * Resolves the view and enforces ownership before mutating.
 *
 * Throws NotFoundError when the view does not exist (or lives in a different
 * port) and ForbiddenError when it belongs to a different user. The 404-
 * before-403 split matches the rest of the API and avoids leaking the
 * existence of another user's saved view via timing or status code.
 */
async function assertViewOwner(id: string, portId: string, userId: string): Promise<void> {
  const view = await db.query.savedViews.findFirst({
    where: and(eq(savedViews.id, id), eq(savedViews.portId, portId)),
  });
  if (!view) throw new NotFoundError('saved view');
  if (view.userId !== userId) throw new ForbiddenError('That saved view belongs to someone else.');
}

export async function patchHandler(
  req: Request,
  ctx: AuthContext,
  params: { id?: string },
): Promise<NextResponse> {
  try {
    const id = params.id ?? '';
    await assertViewOwner(id, ctx.portId, ctx.userId);
    const body = await parseBody(req as never, updateSavedViewSchema);
    const view = await savedViewsService.update(ctx.portId, ctx.userId, id, body);
    return NextResponse.json({ data: view });
  } catch (error) {
    return errorResponse(error);
  }
}

export async function deleteHandler(
  _req: Request,
  ctx: AuthContext,
  params: { id?: string },
): Promise<NextResponse> {
  try {
    const id = params.id ?? '';
    await assertViewOwner(id, ctx.portId, ctx.userId);
    await savedViewsService.delete(ctx.portId, ctx.userId, id);
    return NextResponse.json({ data: null }, { status: 200 });
  } catch (error) {
    return errorResponse(error);
  }
}
