const prisma = require("./client")

function normalizeIds(ids = []) {
  return Array.from(
    new Set(
      (Array.isArray(ids) ? ids : [])
        .map((id) => Number(id))
        .filter((id) => Number.isInteger(id) && id > 0)
    )
  )
}

async function ensureTotalsForDealIds(dealIds = []) {
  const ids = normalizeIds(dealIds)
  if (!ids.length) return 0
  const existing = await prisma.deal.findMany({
    where: { id: { in: ids } },
    select: { id: true },
  })
  const existingIds = new Set(existing.map((d) => d.id))
  if (!existingIds.size) return 0
  const data = ids.filter((id) => existingIds.has(id)).map((dealId) => ({ dealId }))
  const result = await prisma.dealAnalyticsTotal.createMany({
    data,
    skipDuplicates: true,
  })
  return result?.count ?? 0
}

async function getTotalsByDealIds(dealIds = []) {
  const ids = normalizeIds(dealIds)
  if (!ids.length) return []
  return prisma.dealAnalyticsTotal.findMany({
    where: { dealId: { in: ids } },
    select: {
      dealId: true,
      impressions: true,
      views: true,
      clicks: true,
    },
  })
}

function aggregateEventIncrements(events = []) {
  const byDeal = new Map()
  for (const event of events) {
    const dealId = Number(event.dealId)
    if (!Number.isInteger(dealId) || dealId <= 0) continue
    const type = String(event.type || "").toUpperCase()
    const entry = byDeal.get(dealId) || { dealId, impressions: 0, views: 0, clicks: 0 }
    if (type === "IMPRESSION") entry.impressions += 1
    else if (type === "VIEW") entry.views += 1
    else if (type === "CLICK") entry.clicks += 1
    byDeal.set(dealId, entry)
  }
  return Array.from(byDeal.values())
}

async function applyDealEventBatch(events = []) {
  const filtered = (Array.isArray(events) ? events : []).filter(
    (e) => e && e.dealId && (e.userId || e.ip)
  )
  if (!filtered.length) return { inserted: 0, increments: [] }

  const data = filtered.map((event) => ({
    dealId: Number(event.dealId),
    type: String(event.type || "IMPRESSION").toUpperCase(),
    userId: event.userId ? Number(event.userId) : null,
    ip: event.ip ? String(event.ip) : null,
    createdAt: event.createdAt ? new Date(event.createdAt) : new Date(),
  }))

  const increments = aggregateEventIncrements(data)

  await prisma.$transaction(async (tx) => {
    await tx.dealEvent.createMany({ data })

    for (const inc of increments) {
      await tx.dealAnalyticsTotal.upsert({
        where: { dealId: inc.dealId },
        create: {
          dealId: inc.dealId,
          impressions: inc.impressions,
          views: inc.views,
          clicks: inc.clicks,
        },
        update: {
          impressions: { increment: inc.impressions },
          views: { increment: inc.views },
          clicks: { increment: inc.clicks },
        },
      })
    }
  })

  return { inserted: data.length, increments }
}

module.exports = {
  ensureTotalsForDealIds,
  getTotalsByDealIds,
  applyDealEventBatch,
}
