const prisma = require("./client")
const { Prisma } = require("@prisma/client")

async function findLike(commentId, userId, db) {
  const p = db || prisma
  return p.commentLike.findUnique({
    where: { commentId_userId: { commentId, userId } },
  })
}

async function findLikesByUserAndCommentIds(userId, commentIds, db) {
  const p = db || prisma
  return p.commentLike.findMany({
    where: { userId, commentId: { in: commentIds } },
    select: { commentId: true },
  })
}

async function setCommentLike({ commentId, userId, like }) {
  return prisma.$transaction(async (tx) => {
    const comment = await tx.comment.findUnique({
      where: { id: commentId },
      select: { id: true, likeCount: true },
    })
    if (!comment) throw new Error("Yorum bulunamadÄ±.")

    const existing = await findLike(commentId, userId, tx)

    if (like) {
      if (existing) {
        return { liked: true, delta: 0, likeCount: comment.likeCount }
      }
      await tx.commentLike.create({
        data: { commentId, userId },
      })
      const updated = await tx.comment.update({
        where: { id: commentId },
        data: { likeCount: { increment: 1 } },
        select: { likeCount: true },
      })
      return { liked: true, delta: 1, likeCount: updated.likeCount }
    }

    if (!existing) {
      return { liked: false, delta: 0, likeCount: comment.likeCount }
    }
    await tx.commentLike.delete({
      where: { commentId_userId: { commentId, userId } },
    })
    const updated = await tx.comment.update({
      where: { id: commentId },
      data: { likeCount: { decrement: 1 } },
      select: { likeCount: true },
    })
    return { liked: false, delta: -1, likeCount: updated.likeCount }
  })
}

async function applyCommentLikeBatch(items = []) {
  if (!items.length) return { inserted: 0, deleted: 0 }

  const likes = items.filter((i) => i.like)
  const unlikes = items.filter((i) => !i.like)

  return prisma.$transaction(async (tx) => {
    let inserted = 0
    let deleted = 0

    if (likes.length) {
      const values = Prisma.join(
        likes.map((i) => Prisma.sql`(${i.commentId}, ${i.userId})`)
      )
      const insertSql = Prisma.sql`
        WITH input("commentId","userId") AS (VALUES ${values}),
        ins AS (
          INSERT INTO "CommentLike" ("commentId","userId")
          SELECT "commentId","userId" FROM input
          ON CONFLICT ("commentId","userId") DO NOTHING
          RETURNING "commentId"
        ),
        agg AS (
          SELECT "commentId", COUNT(*)::int AS cnt FROM ins GROUP BY "commentId"
        )
        UPDATE "Comment" c
        SET "likeCount" = c."likeCount" + agg.cnt
        FROM agg
        WHERE c.id = agg."commentId"
        RETURNING agg.cnt
      `

      const rows = await tx.$queryRaw(insertSql)
      if (Array.isArray(rows)) {
        inserted = rows.reduce((sum, row) => sum + Number(row.cnt || 0), 0)
      }
    }

    if (unlikes.length) {
      const values = Prisma.join(
        unlikes.map((i) => Prisma.sql`(${i.commentId}, ${i.userId})`)
      )
      const deleteSql = Prisma.sql`
        WITH input("commentId","userId") AS (VALUES ${values}),
        del AS (
          DELETE FROM "CommentLike" cl
          WHERE (cl."commentId", cl."userId") IN (SELECT "commentId","userId" FROM input)
          RETURNING "commentId"
        ),
        agg AS (
          SELECT "commentId", COUNT(*)::int AS cnt FROM del GROUP BY "commentId"
        )
        UPDATE "Comment" c
        SET "likeCount" = c."likeCount" - agg.cnt
        FROM agg
        WHERE c.id = agg."commentId"
        RETURNING agg.cnt
      `

      const rows = await tx.$queryRaw(deleteSql)
      if (Array.isArray(rows)) {
        deleted = rows.reduce((sum, row) => sum + Number(row.cnt || 0), 0)
      }
    }

    return { inserted, deleted }
  })
}

module.exports = {
  findLikesByUserAndCommentIds,
  setCommentLike,
  applyCommentLikeBatch,
}
