const userDb = require("../db/user.db")
const userNoteDb = require("../db/userNote.db")
const refreshTokenDb = require("../db/refreshToken.db")
const { queueUserUpdate, queueUserNoteCreate } = require("./redis/dbSync.service")
const {
  getOrCacheUserModeration,
  setUserModerationInRedis,
} = require("./redis/userModerationCache.service")

function assertUserId(userId) {
  const id = Number(userId)
  if (!Number.isInteger(id) || id <= 0) {
    const err = new Error("INVALID_USER_ID")
    err.statusCode = 400
    throw err
  }
  return id
}

function computeUntil(durationDays = 7) {
  const days = Number(durationDays)
  const safeDays = Number.isFinite(days) && days > 0 ? days : 7
  return new Date(Date.now() + safeDays * 24 * 60 * 60 * 1000)
}

async function ensureUserExists(userId) {
  const id = assertUserId(userId)
  const existing = await getOrCacheUserModeration(id)
  if (!existing) {
    const err = new Error("USER_NOT_FOUND")
    err.statusCode = 404
    throw err
  }
  return { id, existing }
}

async function updateUserModeration(id, patch) {
  const updatedAt = new Date()
  const payload = { id, ...patch }
  await setUserModerationInRedis(payload, { ttlSeconds: 60 * 60 })
  queueUserUpdate({
    userId: id,
    data: patch,
    updatedAt: updatedAt.toISOString(),
  }).catch((err) => console.error("DB sync user update failed:", err?.message || err))
  return { id, ...patch }
}

async function muteUser(userId, { durationDays = 7 } = {}) {
  const { id } = await ensureUserExists(userId)
  const mutedUntil = computeUntil(durationDays)
  return updateUserModeration(id, { mutedUntil })
}

async function clearMute(userId) {
  const { id } = await ensureUserExists(userId)
  return updateUserModeration(id, { mutedUntil: null })
}

async function suspendUser(userId, { durationDays = 7 } = {}) {
  const { id } = await ensureUserExists(userId)
  const suspendedUntil = computeUntil(durationDays)
  return updateUserModeration(id, { suspendedUntil })
}

async function clearSuspend(userId) {
  const { id } = await ensureUserExists(userId)
  return updateUserModeration(id, { suspendedUntil: null })
}

async function disableUser(userId) {
  const { id } = await ensureUserExists(userId)
  const disabledAt = new Date()
  await refreshTokenDb.revokeAllUserRefreshTokens(id)
  return updateUserModeration(id, { disabledAt })
}

async function enableUser(userId) {
  const { id } = await ensureUserExists(userId)
  return updateUserModeration(id, { disabledAt: null })
}

async function updateUserRole(userId, role) {
  const { id } = await ensureUserExists(userId)
  const normalized = String(role || "").toUpperCase()
  if (!["USER", "MOD"].includes(normalized)) {
    const err = new Error("INVALID_ROLE")
    err.statusCode = 400
    throw err
  }
  return updateUserModeration(id, { role: normalized })
}

async function addUserNote({ userId, createdById, note }) {
  const uid = assertUserId(userId)
  const cid = assertUserId(createdById)
  const text = String(note || "").trim()
  if (!text) {
    const err = new Error("NOTE_REQUIRED")
    err.statusCode = 400
    throw err
  }

  queueUserNoteCreate({
    userId: uid,
    createdById: cid,
    note: text.slice(0, 1000),
    createdAt: new Date().toISOString(),
  }).catch((err) => console.error("DB sync user note failed:", err?.message || err))

  return { userId: uid, createdById: cid, note: text.slice(0, 1000) }
}

async function listUserNotes({ userId, page = 1, limit = 20 }) {
  const uid = assertUserId(userId)
  const safePage = Number.isInteger(Number(page)) && Number(page) > 0 ? Number(page) : 1
  const safeLimit = Number.isInteger(Number(limit)) && Number(limit) > 0 ? Number(limit) : 20
  const skip = (safePage - 1) * safeLimit

  const [notes, total, userExists] = await Promise.all([
    userNoteDb.listUserNotes({ userId: uid, skip, take: safeLimit }),
    userNoteDb.countUserNotes({ userId: uid }),
    userDb.findUser({ id: uid }, { select: { id: true } }).then((u) => Boolean(u)),
  ])

  if (!userExists) {
    const err = new Error("USER_NOT_FOUND")
    err.statusCode = 404
    throw err
  }

  return {
    page: safePage,
    total,
    totalPages: total ? Math.ceil(total / safeLimit) : 0,
    results: notes,
  }
}

module.exports = {
  muteUser,
  clearMute,
  suspendUser,
  clearSuspend,
  disableUser,
  enableUser,
  updateUserRole,
  addUserNote,
  listUserNotes,
}
