eletrotupi / tcc / api/src/lib/queue/processors/insights/dailyEnergy.ts master
2.8 KB Raw
import { prisma } from "@app/lib/prisma";
import { InsightType, InsightPeriod } from "@prisma/client";
import { InsightPeriodPayload } from "@app/lib/queue/types";
import { avg } from "@app/utils/calc";

export async function processDailyEnergy({
  userId,
  periodStart,
  periodEnd,
}: InsightPeriodPayload): Promise<void> {
  const start = new Date(periodStart);
  const end = new Date(periodEnd);

  const moods = await prisma.mood.findMany({
    where: { userId, moment: { gte: start, lte: end } },
    orderBy: { moment: "asc" },
    select: {
      energyLevel: true,
      stressLevel: true,
      anxietyLevel: true,
      selectedMood: true,
      moment: true,
    },
  });

  if (moods.length === 0) return;

  const avgEnergy = parseFloat(avg(moods.map((m) => m.energyLevel)).toFixed(2));
  const avgStress = parseFloat(avg(moods.map((m) => m.stressLevel)).toFixed(2));
  const avgAnxiety = parseFloat(
    avg(moods.map((m) => m.anxietyLevel)).toFixed(2),
  );
  const peak = Math.max(...moods.map((m) => m.energyLevel));
  const trough = Math.min(...moods.map((m) => m.energyLevel));

  // Trend across the day: compare first half vs second half entries
  // Not that great, but it works
  const mid = Math.floor(moods.length / 2);
  const morningAvg =
    moods.length > 1
      ? avg(moods.slice(0, mid).map((m) => m.energyLevel))
      : null;

  const eveningAvg =
    moods.length > 1 ? avg(moods.slice(mid).map((m) => m.energyLevel)) : null;

  const dayTrend =
    morningAvg && eveningAvg
      ? parseFloat((((eveningAvg - morningAvg) / morningAvg) * 100).toFixed(1))
      : null;

  await prisma.insight.upsert({
    where: {
      userId_type_periodStart: {
        userId,
        type: InsightType.DAILY_ENERGY,
        periodStart: start,
      },
    },
    update: {
      body: buildBody(avgEnergy, dayTrend),
      metadata: {
        avgEnergy,
        avgStress,
        avgAnxiety,
        peak,
        trough,
        dayTrend,
        entryCount: moods.length,
      },
      generatedAt: new Date(),
    },
    create: {
      userId,
      type: InsightType.DAILY_ENERGY,
      period: InsightPeriod.DAILY,
      title: "Energia do Dia",
      body: buildBody(avgEnergy, dayTrend),
      metadata: {
        avgEnergy,
        avgStress,
        avgAnxiety,
        peak,
        trough,
        dayTrend,
        entryCount: moods.length,
      },
      periodStart: start,
      periodEnd: end,
    },
  });
}

function buildBody(avgEnergy: number, dayTrend: number | null): string {
  const level = avgEnergy >= 7 ? "alta" : avgEnergy >= 4 ? "moderada" : "baixa";
  if (dayTrend === null) return `Energia ${level} hoje.`;
  if (dayTrend > 10)
    return `Energia ${level} hoje, com melhora ao longo do dia.`;
  if (dayTrend < -10)
    return `Energia ${level} hoje, com queda ao longo do dia.`;
  return `Energia ${level} e estável ao longo do dia.`;
}