const dealDb = require("../db/deal.db");
const { updateDealVoteInRedis } = require("./redis/dealVote.service");
const { queueVoteUpdate, queueDealUpdate, queueNotificationCreate } = require("./redis/dbSync.service");
const { updateDealInRedis } = require("./redis/dealCache.service");
const { publishNotification } = require("./redis/notificationPubsub.service");

async function voteDeal({ dealId, userId, voteType }) {
  if (!dealId || !userId || voteType === undefined) {
    const err = new Error("Eksik veri");
    err.statusCode = 400;
    throw err;
  }

  if (![ -1, 0, 1 ].includes(voteType)) {
    const err = new Error("voteType -1, 0 veya 1 olmalı");
    err.statusCode = 400;
    throw err;
  }

  const deal = await dealDb.findDeal(
    { id: Number(dealId) },
    { select: { status: true } }
  );
  if (!deal || !["ACTIVE", "EXPIRED"].includes(deal.status)) {
    const err = new Error("deal sadece ACTIVE veya EXPIRED iken oylanabilir");
    err.statusCode = 400;
    throw err;
  }

  const createdAt = new Date();

  const redisResult = await updateDealVoteInRedis({
    dealId,
    userId,
    voteType,
  }).catch((err) => {
    console.error("Redis vote update failed:", err?.message || err);
    return { updated: false, delta: 0, score: null, maxNotifiedMilestone: 0, dealUserId: null };
  });

  queueVoteUpdate({
    dealId,
    userId,
    voteType,
    createdAt: createdAt.toISOString(),
  }).catch((err) => console.error("DB sync vote queue failed:", err?.message || err));

  const scoreVal = Number(redisResult?.score)
  const maxNotified = Number(redisResult?.maxNotifiedMilestone ?? 0)
  const ownerId = Number(redisResult?.dealUserId)
  if (Number.isFinite(scoreVal) && Number.isInteger(ownerId) && ownerId > 0) {
    const milestone = 100
    if (scoreVal >= milestone && maxNotified < milestone) {
      const updatedAt = new Date()
      await updateDealInRedis(dealId, { maxNotifiedMilestone: milestone }, { updatedAt }).catch((err) =>
        console.error("Redis deal milestone update failed:", err?.message || err)
      )
      queueDealUpdate({
        dealId,
        data: { maxNotifiedMilestone: milestone },
        updatedAt: updatedAt.toISOString(),
      }).catch((err) => console.error("DB sync deal milestone update failed:", err?.message || err))
      queueNotificationCreate({
        userId: ownerId,
        message: "Fırsatın 100 beğeniyi geçti!",
        type: "MILESTONE",
        createdAt: updatedAt.toISOString(),
      }).catch((err) => console.error("DB sync notification queue failed:", err?.message || err))
      publishNotification({
        userId: ownerId,
        message: "Fırsatın 100 beğeniyi geçti!",
        type: "MILESTONE",
        createdAt: updatedAt.toISOString(),
      }).catch((err) => console.error("Notification publish failed:", err?.message || err))
    }
  }

  // Fallback: Redis yoksa mevcut DB'den approx hesapla
  let delta = redisResult?.delta ?? 0;
  let score = redisResult?.score ?? null;
  if (score === null) {
    const current = await dealDb.findDeal(
      { id: Number(dealId) },
      { select: { score: true, votes: { where: { userId: Number(userId) }, select: { voteType: true } } } }
    );
    const oldVote = current?.votes?.[0]?.voteType ?? 0;
    delta = Number(voteType) - Number(oldVote);
    score = Number(current?.score ?? 0) + delta;
  }

  return {
    dealId,
    voteType,
    delta,
    score,
  };
}

async function getVotes(dealId) {
  const votes = await voteDb.findVotes(
    { dealId },
    {
      select: {
        id: true,
        dealId: true,
        userId: true,
        voteType: true,
        createdAt: true,
        lastVotedAt: true,
      },
      orderBy: { createdAt: "desc" },
    }
  )

  return votes.map((vote) => ({
    ...vote,
    createdAt: vote.createdAt.toISOString(),
    lastVotedAt: vote.lastVotedAt.toISOString(),
  }))
}

module.exports = { voteDeal, getVotes };
