const { getRedisClient } = require("./client")
const { ensureMinDealTtl } = require("./dealCache.service")

function createRedisClient() {
  return getRedisClient()
}

const DEAL_VOTE_HASH_PREFIX = "data:deals:votes:"

async function updateDealVoteInRedis({ dealId, userId, voteType, score }) {
  if (!dealId || !userId) return
  const redis = createRedisClient()

  try {
    const key = `data:deals:${dealId}`
    const voteKey = `${DEAL_VOTE_HASH_PREFIX}${dealId}`
    const raw = await redis.call("JSON.GET", key)
    if (!raw) return { updated: false, delta: 0, score: null }

    const deal = JSON.parse(raw)
    const currentScore = Number.isFinite(deal?.score) ? Number(deal.score) : 0
    const maxNotifiedMilestone = Number.isFinite(deal?.maxNotifiedMilestone)
      ? Number(deal.maxNotifiedMilestone)
      : 0
    const dealUserId = Number(deal?.userId)
    const rawVotes = deal?.votes ?? []

    let votes = []
    votes = Array.isArray(rawVotes) ? rawVotes : []
    const normalizedUserId = Number(userId)
    const normalizedVoteType = Number(voteType)
    const idx = votes.findIndex((vote) => Number(vote.userId) === normalizedUserId)
    const oldVote = idx >= 0 ? Number(votes[idx]?.voteType ?? 0) : 0
    if (idx >= 0) {
      votes[idx] = { userId: normalizedUserId, voteType: normalizedVoteType }
    } else {
      votes.push({ userId: normalizedUserId, voteType: normalizedVoteType })
    }

    await redis.call("JSON.SET", key, "$.votes", JSON.stringify(votes))
    const delta = normalizedVoteType - oldVote
    const nextScore =
      score !== undefined && score !== null ? Number(score) : currentScore + delta
    await redis.call("JSON.SET", key, "$.score", nextScore)
    await redis.hset(voteKey, String(normalizedUserId), String(normalizedVoteType))
    const dealTtl = await redis.ttl(key)
    if (Number.isFinite(dealTtl) && dealTtl > 0) {
      await redis.expire(voteKey, dealTtl)
    }
    await ensureMinDealTtl(dealId, { minSeconds: 15 * 60 })

    return { updated: true, delta, score: nextScore, maxNotifiedMilestone, dealUserId }
  } finally {}
}

async function getDealVoteFromRedis(dealId, userId) {
  const id = Number(dealId)
  const uid = Number(userId)
  if (!Number.isInteger(id) || !Number.isInteger(uid)) return 0
  const redis = createRedisClient()
  try {
    const voteKey = `${DEAL_VOTE_HASH_PREFIX}${id}`
    const raw = await redis.hget(voteKey, String(uid))
    const value = raw == null ? 0 : Number(raw)
    return Number.isFinite(value) ? value : 0
  } finally {}
}

async function getMyVotesForDeals(dealIds = [], userId) {
  const uid = Number(userId)
  if (!Number.isInteger(uid)) return new Map()
  const ids = (Array.isArray(dealIds) ? dealIds : [])
    .map((id) => Number(id))
    .filter((id) => Number.isInteger(id) && id > 0)
  if (!ids.length) return new Map()

  const redis = createRedisClient()
  try {
    const pipeline = redis.pipeline()
    ids.forEach((id) => {
      pipeline.hget(`${DEAL_VOTE_HASH_PREFIX}${id}`, String(uid))
    })
    const results = await pipeline.exec()
    const map = new Map()
    results.forEach(([, raw], idx) => {
      const value = raw == null ? 0 : Number(raw)
      map.set(ids[idx], Number.isFinite(value) ? value : 0)
    })
    return map
  } finally {}
}

module.exports = {
  updateDealVoteInRedis,
  getDealVoteFromRedis,
  getMyVotesForDeals,
}
