eletrotupi / tcc/ api/src/lib/queue/processors/insights/dailyEnergy.ts6b006f28cdcc256212589357ed92e3c06f935c2a
2.8 KB | 102 lines Raw
1
import { prisma } from "@app/lib/prisma";
2
import { InsightType, InsightPeriod } from "@prisma/client";
3
import { InsightPeriodPayload } from "@app/lib/queue/types";
4
import { avg } from "@app/utils/calc";
5

6
export async function processDailyEnergy({
7
  userId,
8
  periodStart,
9
  periodEnd,
10
}: InsightPeriodPayload): Promise<void> {
11
  const start = new Date(periodStart);
12
  const end = new Date(periodEnd);
13

14
  const moods = await prisma.mood.findMany({
15
    where: { userId, moment: { gte: start, lte: end } },
16
    orderBy: { moment: "asc" },
17
    select: {
18
      energyLevel: true,
19
      stressLevel: true,
20
      anxietyLevel: true,
21
      selectedMood: true,
22
      moment: true,
23
    },
24
  });
25

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

28
  const avgEnergy = parseFloat(avg(moods.map((m) => m.energyLevel)).toFixed(2));
29
  const avgStress = parseFloat(avg(moods.map((m) => m.stressLevel)).toFixed(2));
30
  const avgAnxiety = parseFloat(
31
    avg(moods.map((m) => m.anxietyLevel)).toFixed(2),
32
  );
33
  const peak = Math.max(...moods.map((m) => m.energyLevel));
34
  const trough = Math.min(...moods.map((m) => m.energyLevel));
35

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

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

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

52
  await prisma.insight.upsert({
53
    where: {
54
      userId_type_periodStart: {
55
        userId,
56
        type: InsightType.DAILY_ENERGY,
57
        periodStart: start,
58
      },
59
    },
60
    update: {
61
      body: buildBody(avgEnergy, dayTrend),
62
      metadata: {
63
        avgEnergy,
64
        avgStress,
65
        avgAnxiety,
66
        peak,
67
        trough,
68
        dayTrend,
69
        entryCount: moods.length,
70
      },
71
      generatedAt: new Date(),
72
    },
73
    create: {
74
      userId,
75
      type: InsightType.DAILY_ENERGY,
76
      period: InsightPeriod.DAILY,
77
      title: "Energia do Dia",
78
      body: buildBody(avgEnergy, dayTrend),
79
      metadata: {
80
        avgEnergy,
81
        avgStress,
82
        avgAnxiety,
83
        peak,
84
        trough,
85
        dayTrend,
86
        entryCount: moods.length,
87
      },
88
      periodStart: start,
89
      periodEnd: end,
90
    },
91
  });
92
}
93

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