const userDB = require("../db/user.db")
const commentDB = require("../db/comment.db")
const {
  addCommentToRedis,
  removeCommentFromRedis,
  getCommentsForDeal,
} = require("./redis/commentCache.service")
const { getOrCacheDeal, getDealIdByCommentId } = require("./redis/dealCache.service")
const { generateCommentId } = require("./redis/commentId.service")
const { queueCommentCreate, queueCommentDelete } = require("./redis/dbSync.service")

function parseParentId(value) {
  if (value === undefined || value === null || value === "" || value === "null") return null
  const pid = Number(value)
  if (!Number.isInteger(pid) || pid <= 0) throw new Error("Gecersiz parentId.")
  return pid
}

function normalizeSort(value) {
  const normalized = String(value || "new").trim().toLowerCase()
  if (["top", "best", "liked"].includes(normalized)) return "TOP"
  return "NEW"
}

async function ensureDealCached(dealId) {
  return getOrCacheDeal(dealId, { ttlSeconds: 15 * 60 })
}

async function getCommentsByDealId(dealId, { parentId, page, limit, sort, viewer } = {}) {
  const id = Number(dealId)
  const deal = await ensureDealCached(id)
  if (!deal) throw new Error("Deal bulunamadi.")

  return getCommentsForDeal({
    dealId: id,
    deal,
    parentId: parseParentId(parentId),
    page,
    limit,
    sort: normalizeSort(sort),
    viewerId: viewer?.userId ?? null,
  })
}

async function createComment({ dealId, userId, text, parentId = null }) {
  if (!text || typeof text !== "string" || !text.trim()) {
    throw new Error("Yorum bos olamaz.")
  }

  const deal = await ensureDealCached(dealId)
  if (!deal) throw new Error("Deal bulunamadi.")
  if (deal.status !== "ACTIVE" && deal.status !== "EXPIRED") {
    throw new Error("Bu deal icin yorum acilamaz.")
  }

  let parent = null
  if (parentId != null) {
    const pid = parseParentId(parentId)
    const comments = Array.isArray(deal.comments) ? deal.comments : []
    const cachedParent = comments.find((c) => Number(c.id) === Number(pid))
    if (!cachedParent || cachedParent.deletedAt) throw new Error("Yanıtlanan yorum bulunamadi.")
    if (Number(cachedParent.dealId) !== Number(dealId)) {
      throw new Error("Yanıtlanan yorum bu deal'a ait degil.")
    }
    parent = { id: cachedParent.id, dealId: cachedParent.dealId }
  }

  const user = await userDB.findUser(
    { id: userId },
    { select: { id: true, username: true, avatarUrl: true } }
  )
  if (!user) throw new Error("Kullanici bulunamadi.")

  const createdAt = new Date()
  const commentId = await generateCommentId()
  const comment = {
    id: commentId,
    text: text.trim(),
    userId,
    dealId,
    parentId: parent ? parent.id : null,
    createdAt,
    likeCount: 0,
    repliesCount: 0,
    user,
  }

  await addCommentToRedis({
    ...comment,
    repliesCount: 0,
  })

  queueCommentCreate({
    commentId,
    dealId,
    userId,
    text: text.trim(),
    parentId: parent ? parent.id : null,
    createdAt: createdAt.toISOString(),
  }).catch((err) => console.error("DB sync comment create failed:", err?.message || err))

  return comment
}

async function deleteComment(commentId, userId) {
  const cid = Number(commentId)
  if (!Number.isInteger(cid) || cid <= 0) throw new Error("Gecersiz commentId.")

  let dealId = await getDealIdByCommentId(cid)
  let dbFallback = null
  if (!dealId) {
    dbFallback = await commentDB.findComment(
      { id: cid },
      { select: { id: true, dealId: true, userId: true, parentId: true, deletedAt: true } }
    )
    if (!dbFallback || dbFallback.deletedAt) throw new Error("Yorum bulunamadi.")
    dealId = dbFallback.dealId
  }

  const deal = await ensureDealCached(dealId)
  if (!deal) throw new Error("Yorum bulunamadi.")

  const comments = Array.isArray(deal.comments) ? deal.comments : []
  const comment = comments.find((c) => Number(c.id) === cid)
  const effective = comment || dbFallback
  if (!effective || effective.deletedAt) throw new Error("Yorum bulunamadi.")
  if (Number(effective.userId) !== Number(userId)) throw new Error("Bu yorumu silme yetkin yok.")

  queueCommentDelete({
    commentId: cid,
    dealId: effective.dealId,
    createdAt: new Date().toISOString(),
  }).catch((err) => console.error("DB sync comment delete failed:", err?.message || err))

  await removeCommentFromRedis({
    commentId: cid,
    dealId: effective.dealId,
  })

  return { message: "Yorum silindi." }
}

async function deleteCommentAsMod(commentId) {
  const cid = Number(commentId)
  if (!Number.isInteger(cid) || cid <= 0) throw new Error("Gecersiz commentId.")

  let dealId = await getDealIdByCommentId(cid)
  let dbFallback = null
  if (!dealId) {
    dbFallback = await commentDB.findComment(
      { id: cid },
      { select: { id: true, dealId: true, userId: true, parentId: true, deletedAt: true } }
    )
    if (!dbFallback || dbFallback.deletedAt) throw new Error("Yorum bulunamadi.")
    dealId = dbFallback.dealId
  }

  const deal = await ensureDealCached(dealId)
  if (!deal) throw new Error("Yorum bulunamadi.")

  const comments = Array.isArray(deal.comments) ? deal.comments : []
  const comment = comments.find((c) => Number(c.id) === cid)
  const effective = comment || dbFallback
  if (!effective || effective.deletedAt) throw new Error("Yorum bulunamadi.")

  queueCommentDelete({
    commentId: cid,
    dealId: effective.dealId,
    createdAt: new Date().toISOString(),
  }).catch((err) => console.error("DB sync comment delete failed:", err?.message || err))

  await removeCommentFromRedis({
    commentId: cid,
    dealId: effective.dealId,
  })

  return { message: "Yorum silindi." }
}

module.exports = {
  getCommentsByDealId,
  createComment,
  deleteComment,
  deleteCommentAsMod,
}
