import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
import { db, comments, commentReactions, eq, and, count } from "@epicure/db";
import { requireSessionOrApiKey } from "@/lib/api-auth";
import { applyRateLimit } from "@/lib/rate-limit";
import { createNotification } from "@/lib/notifications";

const ReactionSchema = z.object({
  type: z.enum(["like", "love", "laugh", "wow", "sad", "fire"]),
});

type Params = { params: Promise<{ id: string; commentId: string }> };

export async function GET(req: NextRequest, { params }: Params) {
  const { commentId } = await params;

  // Verify comment exists
  const comment = await db.query.comments.findFirst({ where: eq(comments.id, commentId) });
  if (!comment) {
    return NextResponse.json({ error: "Not found" }, { status: 404 });
  }

  // Get reaction counts grouped by type
  const rows = await db
    .select({ type: commentReactions.type, cnt: count() })
    .from(commentReactions)
    .where(eq(commentReactions.commentId, commentId))
    .groupBy(commentReactions.type);

  const counts: Record<string, number> = {};
  for (const row of rows) {
    counts[row.type] = row.cnt;
  }

  // Optional auth — GET reactions is public; session present means also return user's own reactions
  // response intentionally ignored: unauthenticated callers get counts only with empty userReactions
  const { session } = await requireSessionOrApiKey(req);
  let userReactions: string[] = [];

  if (session) {
    const userRows = await db
      .select({ type: commentReactions.type })
      .from(commentReactions)
      .where(and(eq(commentReactions.commentId, commentId), eq(commentReactions.userId, session.user.id)));
    userReactions = userRows.map((r) => r.type);
  }

  return NextResponse.json({ counts, userReactions });
}

export async function POST(req: NextRequest, { params }: Params) {
  const { session, response } = await requireSessionOrApiKey(req);
  if (response) return response;

  const limited = await applyRateLimit(`rl:reaction:${session!.user.id}`, 60, 60);
  if (limited) return limited;

  const { commentId } = await params;

  // Verify comment exists
  const comment = await db.query.comments.findFirst({ where: eq(comments.id, commentId) });
  if (!comment) {
    return NextResponse.json({ error: "Not found" }, { status: 404 });
  }

  const body = await req.json() as unknown;
  const parsed = ReactionSchema.safeParse(body);
  if (!parsed.success) return NextResponse.json({ error: "Validation error" }, { status: 400 });

  const { type } = parsed.data;
  const userId = session!.user.id;

  // Toggle: check if reaction exists
  const existing = await db.query.commentReactions.findFirst({
    where: and(
      eq(commentReactions.commentId, commentId),
      eq(commentReactions.userId, userId),
      eq(commentReactions.type, type),
    ),
  });

  let added: boolean;
  if (existing) {
    await db.delete(commentReactions).where(eq(commentReactions.id, existing.id));
    added = false;
  } else {
    await db.insert(commentReactions).values({
      id: crypto.randomUUID(),
      commentId,
      userId,
      type,
    });
    added = true;
    void createNotification({ userId: comment.userId, type: "reaction", actorId: userId, recipeId: comment.recipeId, commentId });
  }

  // Return updated counts
  const rows = await db
    .select({ type: commentReactions.type, cnt: count() })
    .from(commentReactions)
    .where(eq(commentReactions.commentId, commentId))
    .groupBy(commentReactions.type);

  const counts: Record<string, number> = {};
  for (const row of rows) {
    counts[row.type] = row.cnt;
  }

  return NextResponse.json({ counts, added });
}
