Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
82.66% covered (warning)
82.66%
596 / 721
42.86% covered (danger)
42.86%
3 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
FlyMsgUserDailyUsageService
82.66% covered (warning)
82.66%
596 / 721
42.86% covered (danger)
42.86%
3 / 7
58.51
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 refresh
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 processUserSummaryUsage2
99.29% covered (success)
99.29%
140 / 141
0.00% covered (danger)
0.00%
0 / 1
7
 processUserSummaryUsage
99.54% covered (success)
99.54%
215 / 216
0.00% covered (danger)
0.00%
0 / 1
5
 processUserUsage
62.18% covered (warning)
62.18%
171 / 275
0.00% covered (danger)
0.00%
0 / 1
51.61
 parseMonth
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
1
 getHubspotUsage
73.61% covered (warning)
73.61%
53 / 72
0.00% covered (danger)
0.00%
0 / 1
10.49
1<?php
2
3namespace App\Services\UserInfo;
4
5use App\Http\Models\Admin\CompanyGroup;
6use App\Http\Models\Auth\User;
7use App\Http\Models\FlyCutUsage;
8use App\Http\Models\FlyGrammarActions;
9use App\Http\Models\FlyMsgUserDailyUsage;
10use App\Http\Models\HubspotProperties;
11use App\Http\Models\Shortcut;
12use App\Http\Models\UserInfo;
13use App\Http\Services\StatisticsService;
14use App\Traits\UsageTrait;
15use Illuminate\Support\Carbon;
16use MongoDB\BSON\UTCDateTime;
17
18class FlyMsgUserDailyUsageService
19{
20    use UsageTrait;
21
22    public function __construct(
23        private StatisticsService $statisticsService
24    ) {}
25
26    public function refresh(FlyMsgUserDailyUsage $usage): void
27    {
28        $user = User::find($usage->user_id);
29
30        $this->processUserSummaryUsage($user);
31    }
32
33    public function processUserSummaryUsage2(User $user)
34    {
35        $userInfo = UserInfo::where('email', $user->email)->first();
36
37        $startDate = $user->created_at;
38
39        if ($startDate->lessThan(Carbon::parse('2022-01-01 00:00:00'))) {
40            $startDate = Carbon::parse('2022-01-01 00:00:00');
41        }
42
43        $endDate = now()->endOfDay();
44
45        $sentence_rewrite_summarized = [];
46        $paragraph_rewrite_summarized = [];
47        $fly_engage_summarized = [];
48        $fly_post_summarized = [];
49        $fly_cut_summarized = [];
50        $time_saved_summarized = [];
51        $cost_savings_summarized = [];
52        $characters_typed_summarized = [];
53        while ($startDate->lessThanOrEqualTo($endDate)) {
54            $year = $startDate->year;
55            $month = $this->parseMonth($startDate->month);
56
57            $totalTimeSavedThisMonth = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->where('year', $year)->where('month', $startDate->month)->sum('time_saved');
58            $totalCostSavingsThisMonth = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->where('year', $year)->where('month', $startDate->month)->sum('cost_savings');
59            $totalCharactersTypedThisMonth = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->where('year', $year)->where('month', $startDate->month)->sum('characters_typed');
60
61            $userInfo->{"total_time_saved___{$month}_{$year}"} = $totalTimeSavedThisMonth;
62            $userInfo->{"total_cost_savings___{$month}_{$year}"} = $totalCostSavingsThisMonth;
63            $userInfo->{"of_characters_typed___{$month}_{$year}"} = $totalCharactersTypedThisMonth;
64
65            $formattedDate = $startDate->format('M Y');
66
67            if ($year >= 2023) {
68                $totalFlyPostUsedThisMonth = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->where('year', $year)->where('month', $startDate->month)->sum('flypost_count');
69                $totalFlyEngageUsedThisMonth = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->where('year', $year)->where('month', $startDate->month)->sum('flyengage_count');
70                $totalSentenceRewriteUsedThisMonth = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->where('year', $year)->where('month', $startDate->month)->sum('sentence_rewrite_count');
71                $totalParagraphRewriteUsedThisMonth = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->where('year', $year)->where('month', $startDate->month)->sum('paragraph_rewrite_count');
72                $totalFlyCutUsedThisMonth = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->where('year', $year)->where('month', $startDate->month)->sum('flycut_count');
73                $totalFlyGrammarActionsThisMonth = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->where('year', $year)->where('month', $startDate->month)->sum('fly_grammar_actions');
74
75                $sentence_rewrite_summarized[] = [
76                    'date' => $startDate->timestamp,
77                    'month' => $formattedDate,
78                    'total' => $totalSentenceRewriteUsedThisMonth,
79                ];
80
81                $paragraph_rewrite_summarized[] = [
82                    'date' => $startDate->timestamp,
83                    'month' => $formattedDate,
84                    'total' => $totalParagraphRewriteUsedThisMonth,
85                ];
86
87                $fly_engage_summarized[] = [
88                    'date' => $startDate->timestamp,
89                    'month' => $formattedDate,
90                    'total' => $totalFlyEngageUsedThisMonth,
91                ];
92
93                $fly_post_summarized[] = [
94                    'date' => $startDate->timestamp,
95                    'month' => $formattedDate,
96                    'total' => $totalFlyPostUsedThisMonth,
97                ];
98
99                $fly_cut_summarized[] = [
100                    'date' => $startDate->timestamp,
101                    'month' => $formattedDate,
102                    'total' => $totalFlyCutUsedThisMonth,
103                ];
104
105                $fly_grammar_actions_summarized[] = [
106                    'date' => $startDate->timestamp,
107                    'month' => $formattedDate,
108                    'total' => $totalFlyGrammarActionsThisMonth,
109                ];
110            }
111
112            $time_saved_summarized[] = [
113                'date' => $startDate->timestamp,
114                'month' => $formattedDate,
115                'total' => $totalTimeSavedThisMonth,
116            ];
117
118            $cost_savings_summarized[] = [
119                'date' => $startDate->timestamp,
120                'month' => $formattedDate,
121                'total' => $totalCostSavingsThisMonth,
122            ];
123
124            $characters_typed_summarized[] = [
125                'date' => $startDate->timestamp,
126                'month' => $formattedDate,
127                'total' => $totalCharactersTypedThisMonth,
128            ];
129
130            $startDate->addMonth();
131            // if same month as endDate
132            if ($startDate->month == $endDate->month && $startDate->year == $endDate->year && $startDate->greaterThan($endDate)) {
133                $startDate = $endDate->copy();
134            }
135        }
136
137        $time_saved_summarized = collect($time_saved_summarized)->sortByDesc('date')->values();
138        $time_saved_summarized = $time_saved_summarized->map(function ($item) {
139            return $item['total'].' - '.$item['month'];
140        });
141
142        $cost_savings_summarized = collect($cost_savings_summarized)->sortByDesc('date')->values();
143        $cost_savings_summarized = $cost_savings_summarized->map(function ($item) {
144            return $item['total'].' - '.$item['month'];
145        });
146
147        $characters_typed_summarized = collect($characters_typed_summarized)->sortByDesc('date')->values();
148        $characters_typed_summarized = $characters_typed_summarized->map(function ($item) {
149            return $item['total'].' - '.$item['month'];
150        });
151
152        $fly_cut_summarized = collect($fly_cut_summarized)->sortByDesc('date')->values();
153        $fly_cut_summarized = $fly_cut_summarized->map(function ($item) {
154            return $item['total'].' - '.$item['month'];
155        });
156
157        $fly_engage_summarized = collect($fly_engage_summarized)->sortByDesc('date')->values();
158        $fly_engage_summarized = $fly_engage_summarized->map(function ($item) {
159            return $item['total'].' - '.$item['month'];
160        });
161
162        $sentence_rewrite_summarized = collect($sentence_rewrite_summarized)->sortByDesc('date')->values();
163        $sentence_rewrite_summarized = $sentence_rewrite_summarized->map(function ($item) {
164            return $item['total'].' - '.$item['month'];
165        });
166        $paragraph_rewrite_summarized = collect($paragraph_rewrite_summarized)->sortByDesc('date')->values();
167        $paragraph_rewrite_summarized = $paragraph_rewrite_summarized->map(function ($item) {
168            return $item['total'].' - '.$item['month'];
169        });
170
171        $fly_post_summarized = collect($fly_post_summarized)->sortByDesc('date')->values();
172        $fly_post_summarized = $fly_post_summarized->map(function ($item) {
173            return $item['total'].' - '.$item['month'];
174        });
175
176        $fly_grammar_actions_summarized = collect($fly_grammar_actions_summarized)->sortByDesc('date')->values();
177        $fly_grammar_actions_summarized = $fly_grammar_actions_summarized->map(function ($item) {
178            return $item['total'].' - '.$item['month'];
179        });
180
181        $userInfo->total_time_saved_summarized_monthly_by_flymsg_by_user = $time_saved_summarized->implode('.   ');
182        $userInfo->total_cost_savings_summarized_monthly_by_flymsg_by_user = $cost_savings_summarized->implode('.   ');
183        $userInfo->total___of_characters_typed_monthly_by_flymsg_by_user = $characters_typed_summarized->implode('.   ');
184        $userInfo->total___of_times_flycut_is_used_summarized_monthly_by_user__count_ = $fly_cut_summarized->implode('.   ');
185        $userInfo->total___of_times_sentence_rewrite_is_used_summarized_monthly_by_user = $sentence_rewrite_summarized->implode('.   ');
186        $userInfo->total___of_times_paragraph_rewrite_is_used_summarized_monthly_by_user = $paragraph_rewrite_summarized->implode('.   ');
187        $userInfo->total___of_times_flyengage_is_used_summarized_monthly_by_user = $fly_engage_summarized->implode('.   ');
188        $userInfo->total___of_times_flyposts_is_used_summarized_monthly_by_user__count_ = $fly_post_summarized->implode('.   ');
189        $userInfo->total___of_times_flygrammar_is_used_summarized_monthly_by_user__count_ = $fly_grammar_actions_summarized->implode('.   ');
190
191        $userInfo->total___of_times_sentence_rewrite_used__count_ = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->sum('sentence_rewrite_count');
192        $userInfo->total___of_times_paragraph_rewrite_used__count_ = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->sum('paragraph_rewrite_count');
193        $userInfo->total___of_times_flyengage_used__count_ = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->sum('flyengage_count');
194        $userInfo->total___of_times_flyposts_used__count_ = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->sum('flypost_count');
195        $userInfo->total___of_times_flycut_used__count_ = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->sum('flycut_count');
196        $userInfo->total___of_times_flygrammar_used__count_ = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->sum('fly_grammar_actions');
197        $userInfo->total___of_times_flygrammar_accepted_used__count_ = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->sum('fly_grammar_accepted');
198        $userInfo->total___of_times_flygrammar_autocorrect_used__count_ = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->sum('fly_grammar_autocorrect');
199        $userInfo->total___of_times_flygrammar_autocomplete_used__count_ = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->sum('fly_grammar_autocomplete');
200
201        $userInfo->total___of_times_roleplay_used__count_ = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->sum('roleplay_sessions_practiced');
202        $userInfo->total_roleplay_personas_created__count_ = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->sum('roleplay_personas_created');
203        $userInfo->total_roleplay_time_practiced__count_ = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->sum('roleplay_time_practiced');
204
205        $userInfo->total_time_saved_by_flymsg_by_user = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->sum('time_saved');
206        $userInfo->total_cost_savings_by_flymsg_by_user = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->sum('cost_savings');
207        $userInfo->total___of_characters_typed_by_flymsg_by_user = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->sum('characters_typed');
208        $userInfo->number_of_flycuts_created_count = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->sum('flycuts_created');
209        $userInfo->number_of_flyplates_in_flycuts_count = FlyMsgUserDailyUsage::where('user_id', $userInfo->user_id)->sum('flyplates_added');
210
211        $userInfo->save();
212    }
213
214    public function processUserSummaryUsage(User $user)
215    {
216        $userInfo = UserInfo::where('email', $user->email)->first();
217        $startDate = $user->created_at->copy();
218
219        if ($startDate->lessThan(Carbon::parse('2022-01-01 00:00:00'))) {
220            $startDate = Carbon::parse('2022-01-01 00:00:00');
221        }
222
223        $endDate = now()->endOfDay();
224        $user_id = $userInfo->user_id;
225
226        // 1. Consulta agregada mensal com todos os campos relevantes
227        $monthly = FlyMsgUserDailyUsage::raw(function ($collection) use ($user_id, $startDate, $endDate) {
228            return $collection->aggregate([
229                [
230                    '$match' => [
231                        'user_id' => $user_id,
232                        'created_at' => [
233                            '$gte' => new UTCDateTime($startDate->startOfMonth()->timestamp * 1000),
234                            '$lte' => new UTCDateTime($endDate->endOfMonth()->timestamp * 1000),
235                        ],
236                    ],
237                ],
238                [
239                    '$group' => [
240                        '_id' => [
241                            'year' => '$year',
242                            'month' => '$month',
243                        ],
244                        'total_time_saved' => ['$sum' => '$time_saved'],
245                        'total_cost_savings' => ['$sum' => '$cost_savings'],
246                        'total_characters_typed' => ['$sum' => '$characters_typed'],
247                        'flyengage_count' => ['$sum' => '$flyengage_count'],
248                        'sentence_rewrite_count' => ['$sum' => '$sentence_rewrite_count'],
249                        'paragraph_rewrite_count' => ['$sum' => '$paragraph_rewrite_count'],
250                        'flypost_count' => ['$sum' => '$flypost_count'],
251                        'flycut_count' => ['$sum' => '$flycut_count'],
252                        'fly_grammar_actions' => ['$sum' => '$fly_grammar_actions'],
253                        'fly_grammar_accepted' => ['$sum' => '$fly_grammar_accepted'],
254                        'fly_grammar_autocomplete' => ['$sum' => '$fly_grammar_autocomplete'],
255                    ],
256                ],
257                [
258                    '$sort' => ['_id.year' => 1, '_id.month' => 1],
259                ],
260            ]);
261        });
262
263        // 2. Consulta agregada total (não agrupado por mês)
264        $totals = FlyMsgUserDailyUsage::raw(function ($collection) use ($user_id) {
265            return $collection->aggregate([
266                ['$match' => ['user_id' => $user_id]],
267                ['$group' => [
268                    '_id' => null,
269                    'flyengage_count' => ['$sum' => '$flyengage_count'],
270                    'sentence_rewrite_count' => ['$sum' => '$sentence_rewrite_count'],
271                    'paragraph_rewrite_count' => ['$sum' => '$paragraph_rewrite_count'],
272                    'flypost_count' => ['$sum' => '$flypost_count'],
273                    'flycut_count' => ['$sum' => '$flycut_count'],
274                    'total_time_saved' => ['$sum' => '$time_saved'],
275                    'total_cost_savings' => ['$sum' => '$cost_savings'],
276                    'total_characters_typed' => ['$sum' => '$characters_typed'],
277                    'number_of_flycuts_created_count' => ['$sum' => '$flycuts_created'],
278                    'number_of_flyplates_in_flycuts_count' => ['$sum' => '$flyplates_added'],
279                    'fly_grammar_actions' => ['$sum' => '$fly_grammar_actions'],
280                    'fly_grammar_accepted' => ['$sum' => '$fly_grammar_accepted'],
281                    'fly_grammar_autocorrect' => ['$sum' => '$fly_grammar_autocorrect'],
282                    'roleplay_personas_created' => ['$sum' => '$roleplay_personas_created'],
283                    'roleplay_sessions_practiced' => ['$sum' => '$roleplay_sessions_practiced'],
284                    'roleplay_time_practiced' => ['$sum' => '$roleplay_time_practiced'],
285                ]],
286            ]);
287        });
288        $totals = $totals[0] ?? [];
289
290        // 3. Processamento em memória
291        $sentence_rewrite_summarized = [];
292        $paragraph_rewrite_summarized = [];
293        $fly_engage_summarized = [];
294        $fly_post_summarized = [];
295        $fly_cut_summarized = [];
296        $time_saved_summarized = [];
297        $cost_savings_summarized = [];
298        $characters_typed_summarized = [];
299        $fly_grammar_actions_summarized = [];
300        $fly_grammar_accepted_summarized = [];
301        $fly_grammar_autocorrect_summarized = [];
302        $fly_grammar_autocomplete_summarized = [];
303
304        foreach ($monthly as $item) {
305            $year = $item['_id']['year'];
306            $monthNum = $item['_id']['month'];
307            $month = Carbon::createFromDate($year, $monthNum, 1);
308            $monthKey = strtolower($month->format('F'))."_{$year}";
309            $formattedDate = $month->format('M Y');
310            $timestamp = $month->timestamp;
311
312            // Salva nos campos dinâmicos
313            $userInfo->{"total_time_saved___{$monthKey}"} = $item['total_time_saved'];
314            $userInfo->{"total_cost_savings___{$monthKey}"} = $item['total_cost_savings'];
315            $userInfo->{"of_characters_typed___{$monthKey}"} = $item['total_characters_typed'];
316
317            $time_saved_summarized[] = [
318                'date' => $timestamp,
319                'month' => $formattedDate,
320                'total' => $item['total_time_saved'],
321            ];
322            $cost_savings_summarized[] = [
323                'date' => $timestamp,
324                'month' => $formattedDate,
325                'total' => $item['total_cost_savings'],
326            ];
327            $characters_typed_summarized[] = [
328                'date' => $timestamp,
329                'month' => $formattedDate,
330                'total' => $item['total_characters_typed'],
331            ];
332
333            if ($year >= 2023) {
334                $fly_cut_summarized[] = [
335                    'date' => $timestamp,
336                    'month' => $formattedDate,
337                    'total' => $item['flycut_count'],
338                ];
339                $fly_engage_summarized[] = [
340                    'date' => $timestamp,
341                    'month' => $formattedDate,
342                    'total' => $item['flyengage_count'],
343                ];
344                $fly_post_summarized[] = [
345                    'date' => $timestamp,
346                    'month' => $formattedDate,
347                    'total' => $item['flypost_count'],
348                ];
349            }
350            if ($year >= 2025) {
351                $sentence_rewrite_summarized[] = [
352                    'date' => $timestamp,
353                    'month' => $formattedDate,
354                    'total' => $item['sentence_rewrite_count'],
355                ];
356                $paragraph_rewrite_summarized[] = [
357                    'date' => $timestamp,
358                    'month' => $formattedDate,
359                    'total' => $item['paragraph_rewrite_count'],
360                ];
361                $fly_grammar_actions_summarized[] = [
362                    'date' => $timestamp,
363                    'month' => $formattedDate,
364                    'total' => $item['fly_grammar_actions'],
365                ];
366                $fly_grammar_accepted_summarized[] = [
367                    'date' => $timestamp,
368                    'month' => $formattedDate,
369                    'total' => $item['fly_grammar_accepted'],
370                ];
371                $fly_grammar_autocorrect_summarized[] = [
372                    'date' => $timestamp,
373                    'month' => $formattedDate,
374                    'total' => $item['fly_grammar_autocorrect'],
375                ];
376                $fly_grammar_autocomplete_summarized[] = [
377                    'date' => $timestamp,
378                    'month' => $formattedDate,
379                    'total' => $item['fly_grammar_autocomplete'],
380                ];
381            }
382        }
383
384        // Ordene e formate os arrays
385        $time_saved_summarized = collect($time_saved_summarized)->sortByDesc('date')->values()->map(function ($item) {
386            return $item['total'].' - '.$item['month'];
387        });
388
389        $cost_savings_summarized = collect($cost_savings_summarized)->sortByDesc('date')->values()->map(function ($item) {
390            return $item['total'].' - '.$item['month'];
391        });
392
393        $characters_typed_summarized = collect($characters_typed_summarized)->sortByDesc('date')->values()->map(function ($item) {
394            return $item['total'].' - '.$item['month'];
395        });
396
397        $fly_cut_summarized = collect($fly_cut_summarized)->sortByDesc('date')->values()->map(function ($item) {
398            return $item['total'].' - '.$item['month'];
399        });
400
401        $fly_engage_summarized = collect($fly_engage_summarized)->sortByDesc('date')->values()->map(function ($item) {
402            return $item['total'].' - '.$item['month'];
403        });
404
405        $sentence_rewrite_summarized = collect($sentence_rewrite_summarized)->sortByDesc('date')->values()->map(function ($item) {
406            return $item['total'].' - '.$item['month'];
407        });
408
409        $paragraph_rewrite_summarized = collect($paragraph_rewrite_summarized)->sortByDesc('date')->values()->map(function ($item) {
410            return $item['total'].' - '.$item['month'];
411        });
412
413        $fly_post_summarized = collect($fly_post_summarized)->sortByDesc('date')->values()->map(function ($item) {
414            return $item['total'].' - '.$item['month'];
415        });
416
417        $fly_grammar_actions_summarized = collect($fly_grammar_actions_summarized)->sortByDesc('date')->values()->map(function ($item) {
418            return $item['total'].' - '.$item['month'];
419        });
420        $fly_grammar_accepted_summarized = collect($fly_grammar_accepted_summarized)->sortByDesc('date')->values()->map(function ($item) {
421            return $item['total'].' - '.$item['month'];
422        });
423        $fly_grammar_autocorrect_summarized = collect($fly_grammar_autocorrect_summarized)->sortByDesc('date')->values()->map(function ($item) {
424            return $item['total'].' - '.$item['month'];
425        });
426        $fly_grammar_autocomplete_summarized = collect($fly_grammar_autocomplete_summarized)->sortByDesc('date')->values()->map(function ($item) {
427            return $item['total'].' - '.$item['month'];
428        });
429
430        // Monte os campos finais
431        $userInfo->total_time_saved_summarized_monthly_by_flymsg_by_user = $time_saved_summarized->implode('.   ');
432        $userInfo->total_cost_savings_summarized_monthly_by_flymsg_by_user = $cost_savings_summarized->implode('.   ');
433        $userInfo->total___of_characters_typed_monthly_by_flymsg_by_user = $characters_typed_summarized->implode('.   ');
434        $userInfo->total___of_times_flycut_is_used_summarized_monthly_by_user__count_ = $fly_cut_summarized->implode('.   ');
435        $userInfo->total___of_times_sentence_rewrite_is_used_summarized_monthly_by_user = $sentence_rewrite_summarized->implode('.   ');
436        $userInfo->total___of_times_paragraph_rewrite_is_used_summarized_monthly_by_user = $paragraph_rewrite_summarized->implode('.   ');
437        $userInfo->total___of_times_flyengage_is_used_summarized_monthly_by_user = $fly_engage_summarized->implode('.   ');
438        $userInfo->total___of_times_flyposts_is_used_summarized_monthly_by_user__count_ = $fly_post_summarized->implode('.   ');
439        $userInfo->total___of_times_flygrammar_is_used_summarized_monthly_by_user = $fly_grammar_actions_summarized->implode('.   ');
440        $userInfo->total___of_times_flygrammar_accepted_is_used_summarized_monthly_by_user = $fly_grammar_accepted_summarized->implode('.   ');
441        $userInfo->total___of_times_flygrammar_autocorrect_is_used_summarized_monthly_by_user = $fly_grammar_autocorrect_summarized->implode('.   ');
442        $userInfo->total___of_times_flygrammar_autocomplete_is_used_summarized_monthly_by_user = $fly_grammar_autocomplete_summarized->implode('.   ');
443
444        // Atualize os campos de totais absolutos
445        $userInfo->total___of_times_sentence_rewrite_used__count_ = $totals['sentence_rewrite_count'] ?? 0;
446        $userInfo->total___of_times_paragraph_rewrite_used__count_ = $totals['paragraph_rewrite_count'] ?? 0;
447        $userInfo->total___of_times_flyengage_used__count_ = $totals['flyengage_count'] ?? 0;
448        $userInfo->total___of_times_flyposts_used__count_ = $totals['flypost_count'] ?? 0;
449        $userInfo->total___of_times_flycut_used__count_ = $totals['flycut_count'] ?? 0;
450        $userInfo->total___of_times_flygrammar_is_used_count = $totals['fly_grammar_actions'] ?? 0;
451        $userInfo->total___of_times_flygrammar_accepted_is_used_count = $totals['fly_grammar_accepted'] ?? 0;
452        $userInfo->total___of_times_flygrammar_autocorrect_is_used_count = $totals['fly_grammar_autocorrect'] ?? 0;
453        $userInfo->total___of_times_flygrammar_autocomplete_is_used_count = $totals['fly_grammar_autocomplete'] ?? 0;
454        $userInfo->total___of_times_roleplay_used__count_ = $totals['roleplay_sessions_practiced'] ?? 0;
455        $userInfo->total_roleplay_personas_created__count_ = $totals['roleplay_personas_created'] ?? 0;
456        $userInfo->total_roleplay_time_practiced__count_ = $totals['roleplay_time_practiced'] ?? 0;
457        $userInfo->total_time_saved_by_flymsg_by_user = $totals['total_time_saved'] ?? 0;
458        $userInfo->total_cost_savings_by_flymsg_by_user = $totals['total_cost_savings'] ?? 0;
459        $userInfo->total___of_characters_typed_by_flymsg_by_user = $totals['total_characters_typed'] ?? 0;
460        $userInfo->number_of_flycuts_created_count = $totals['number_of_flycuts_created_count'] ?? 0;
461        $userInfo->number_of_flyplates_in_flycuts_count = $totals['number_of_flyplates_in_flycuts_count'] ?? 0;
462
463        $userInfo->save();
464    }
465
466    public function processUserUsage(User $user, bool $onlyUpdate = false): void
467    {
468        $startDate = $user->created_at->copy();
469
470        if ($startDate->lessThan(Carbon::parse('2022-01-01 00:00:00'))) {
471            $startDate = Carbon::parse('2022-01-01 00:00:00');
472        }
473
474        if ($onlyUpdate) {
475            $lastRegister = FlyMsgUserDailyUsage::where('user_id', $user->id)->orderBy('created_at', 'desc')->first();
476            if ($lastRegister) {
477                $startDate = $lastRegister->created_at->copy();
478            }
479        }
480
481        $endDate = now();
482
483        $user_id = $user->id;
484        $email_domain = strrchr($user->email, '@');
485        $user_status = $user->status ?? 'Active';
486        $hubspot_id = $user->hubspot_id;
487        $company_id = $user->company_id;
488
489        $group = CompanyGroup::find($user->company_group_id);
490        if (! empty($group?->parent_id)) {
491            $subgroup_id = $user->company_group_id;
492            $group_id = $group->parent_id;
493        } else {
494            $group_id = $user->company_group_id;
495            $subgroup_id = null;
496        }
497
498        $category = $company_id ? 'corporate' : 'individual';
499
500        // 1. Array associativo para todas as datas
501        $merged = [];
502
503        if ($startDate->lessThan(Carbon::parse('2023-02-01 00:00:00'))) {
504            // -------- HUBSPOT USAGE --------
505            $hubspotData = $this->getHubspotUsage($user_id); // igual ao anterior
506            foreach ($hubspotData as $month => $data) {
507                $formatted = ucwords(str_replace('_', ' ', $month)); // "April 2022"
508                $date = Carbon::createFromFormat('F Y', $formatted)->startOfMonth()->copy();
509                $daysInMonth = $date->daysInMonth;
510
511                for ($i = 1; $i <= $daysInMonth; $i++) {
512                    $dt = $date->copy()->day($i);
513                    $key = $dt->toDateString();
514                    if (! isset($merged[$key])) {
515                        $merged[$key] = [];
516                    }
517                    $merged[$key]['characters_typed'] = $data['characters_per_day'] ?? 0;
518                    $merged[$key]['cost_savings'] = $data['cost_per_day'] ?? 0;
519                    $merged[$key]['time_saved'] = $data['time_saved_per_day'] ?? 0;
520                    // Os outros campos virão depois
521                }
522            }
523        }
524
525        // -------- FLYCUT USAGE --------
526        $usages = FlyCutUsage::raw(function ($collection) use ($user_id, $startDate, $endDate) {
527            return $collection->aggregate([
528                ['$match' => [
529                    'user_id' => $user_id,
530                    'created_at' => [
531                        '$gte' => new UTCDateTime(strtotime($startDate->toDateString()) * 1000),
532                        '$lte' => new UTCDateTime(strtotime($endDate->toDateString()) * 1000),
533                    ],
534                ]],
535                ['$group' => [
536                    '_id' => [
537                        'year' => ['$year' => '$created_at'],
538                        'month' => ['$month' => '$created_at'],
539                        'day' => ['$dayOfMonth' => '$created_at'],
540                    ],
541                    'time_saved' => ['$sum' => '$time_saved'],
542                    'cost_savings' => ['$sum' => '$cost_saved'],
543                    'characters_typed' => ['$sum' => '$characters_saved'],
544                    'sentence_rewrite_count' => ['$sum' => ['$cond' => [['$eq' => ['$feature', 'sentence_rewrite']], 1, 0]]],
545                    'paragraph_rewrite_count' => ['$sum' => ['$cond' => [['$eq' => ['$feature', 'paragraph_rewrite']], 1, 0]]],
546                    'flyengage_count' => ['$sum' => ['$cond' => [['$eq' => ['$feature', 'flyengage']], 1, 0]]],
547                    'flypost_count' => ['$sum' => ['$cond' => [['$eq' => ['$feature', 'flypost']], 1, 0]]],
548                    'flycut_count' => ['$sum' => ['$cond' => [['$or' => [['$eq' => ['$feature', null]], ['$not' => ['$feature']]]], 1, 0]]],
549                ]],
550                ['$project' => [
551                    '_id' => 0,
552                    'year' => '$_id.year',
553                    'month' => '$_id.month',
554                    'day' => '$_id.day',
555                    'time_saved' => 1,
556                    'cost_savings' => 1,
557                    'characters_typed' => 1,
558                    'sentence_rewrite_count' => 1,
559                    'paragraph_rewrite_count' => 1,
560                    'flyengage_count' => 1,
561                    'flypost_count' => 1,
562                    'flycut_count' => 1,
563                ]],
564            ]);
565        });
566
567        foreach ($usages as $data) {
568            $dt = Carbon::createFromDate($data['year'], $data['month'], $data['day']);
569            $key = $dt->toDateString();
570            if (! isset($merged[$key])) {
571                $merged[$key] = [];
572            }
573            $merged[$key]['time_saved'] = $data['time_saved'] ?? 0;
574            $merged[$key]['cost_savings'] = $data['cost_savings'] ?? 0;
575            $merged[$key]['characters_typed'] = $data['characters_typed'] ?? 0;
576            $merged[$key]['sentence_rewrite_count'] = $data['sentence_rewrite_count'] ?? 0;
577            $merged[$key]['paragraph_rewrite_count'] = $data['paragraph_rewrite_count'] ?? 0;
578            $merged[$key]['flyengage_count'] = $data['flyengage_count'] ?? 0;
579            $merged[$key]['flypost_count'] = $data['flypost_count'] ?? 0;
580            $merged[$key]['flycut_count'] = $data['flycut_count'] ?? 0;
581        }
582
583        // -------- FLYCUT USAGE --------
584        $usages = FlyCutUsage::raw(function ($collection) use ($user_id, $startDate, $endDate) {
585            return $collection->aggregate([
586                ['$match' => [
587                    'user_id' => $user_id,
588                    'created_at' => [
589                        '$gte' => new UTCDateTime(strtotime($startDate->toDateString()) * 1000),
590                        '$lte' => new UTCDateTime(strtotime($endDate->toDateString()) * 1000),
591                    ],
592                ]],
593                ['$group' => [
594                    '_id' => [
595                        'year' => ['$year' => '$created_at'],
596                        'month' => ['$month' => '$created_at'],
597                        'day' => ['$dayOfMonth' => '$created_at'],
598                    ],
599                    'time_saved' => ['$sum' => '$time_saved'],
600                    'cost_savings' => ['$sum' => '$cost_saved'],
601                    'characters_typed' => ['$sum' => '$characters_saved'],
602                    'sentence_rewrite_count' => ['$sum' => ['$cond' => [['$eq' => ['$feature', 'sentence_rewrite']], 1, 0]]],
603                    'paragraph_rewrite_count' => ['$sum' => ['$cond' => [['$eq' => ['$feature', 'paragraph_rewrite']], 1, 0]]],
604                    'flyengage_count' => ['$sum' => ['$cond' => [['$eq' => ['$feature', 'flyengage']], 1, 0]]],
605                    'flypost_count' => ['$sum' => ['$cond' => [['$eq' => ['$feature', 'flypost']], 1, 0]]],
606                    'flycut_count' => ['$sum' => ['$cond' => [['$or' => [['$eq' => ['$feature', null]], ['$not' => ['$feature']]]], 1, 0]]],
607                ]],
608                ['$project' => [
609                    '_id' => 0,
610                    'year' => '$_id.year',
611                    'month' => '$_id.month',
612                    'day' => '$_id.day',
613                    'time_saved' => 1,
614                    'cost_savings' => 1,
615                    'characters_typed' => 1,
616                    'sentence_rewrite_count' => 1,
617                    'paragraph_rewrite_count' => 1,
618                    'flyengage_count' => 1,
619                    'flypost_count' => 1,
620                    'flycut_count' => 1,
621                ]],
622            ]);
623        });
624
625        foreach ($usages as $data) {
626            $dt = Carbon::createFromDate($data['year'], $data['month'], $data['day']);
627            $key = $dt->toDateString();
628            if (! isset($merged[$key])) {
629                $merged[$key] = [];
630            }
631            $merged[$key]['time_saved'] = $data['time_saved'] ?? 0;
632            $merged[$key]['cost_savings'] = $data['cost_savings'] ?? 0;
633            $merged[$key]['characters_typed'] = $data['characters_typed'] ?? 0;
634            $merged[$key]['sentence_rewrite_count'] = $data['sentence_rewrite_count'] ?? 0;
635            $merged[$key]['paragraph_rewrite_count'] = $data['paragraph_rewrite_count'] ?? 0;
636            $merged[$key]['flyengage_count'] = $data['flyengage_count'] ?? 0;
637            $merged[$key]['flypost_count'] = $data['flypost_count'] ?? 0;
638            $merged[$key]['flycut_count'] = $data['flycut_count'] ?? 0;
639        }
640
641        // -------- SHORTCUTS --------
642        $shortcuts = Shortcut::raw(function ($collection) use ($user_id, $startDate, $endDate) {
643            return $collection->aggregate([
644                ['$match' => [
645                    'user_id' => $user_id,
646                    'created_at' => [
647                        '$gte' => new UTCDateTime(strtotime($startDate->toDateString()) * 1000),
648                        '$lte' => new UTCDateTime(strtotime($endDate->toDateString()) * 1000),
649                    ],
650                ]],
651                ['$group' => [
652                    '_id' => [
653                        'year' => ['$year' => '$created_at'],
654                        'month' => ['$month' => '$created_at'],
655                        'day' => ['$dayOfMonth' => '$created_at'],
656                        'user_defined' => '$user_defined',
657                    ],
658                    'count' => ['$sum' => 1],
659                ]],
660                ['$project' => [
661                    '_id' => 0,
662                    'year' => '$_id.year',
663                    'month' => '$_id.month',
664                    'day' => '$_id.day',
665                    'user_defined' => '$_id.user_defined',
666                    'count' => 1,
667                ]],
668            ]);
669        });
670
671        foreach ($shortcuts as $data) {
672            $dt = Carbon::createFromDate($data['year'], $data['month'], $data['day']);
673            $key = $dt->toDateString();
674            if (! isset($merged[$key])) {
675                $merged[$key] = [];
676            }
677            $merged[$key]['flycuts_created'] = ($data['user_defined'] ?? false) ? $data['count'] : 0;
678            $merged[$key]['flyplates_added'] = (! ($data['user_defined'] ?? false)) ? $data['count'] : 0;
679        }
680
681        // -------- FLYGRAMMAR USAGE --------
682        $actionsUsage = FlyGrammarActions::raw(function ($collection) use ($user_id, $startDate, $endDate) {
683            return $collection->aggregate([
684                ['$match' => [
685                    'user_id' => $user_id,
686                    'created_at' => [
687                        '$gte' => new UTCDateTime(strtotime($startDate->toDateString()) * 1000),
688                        '$lte' => new UTCDateTime(strtotime($endDate->toDateString()) * 1000),
689                    ],
690                ]],
691                ['$group' => [
692                    '_id' => [
693                        'year' => ['$year' => '$created_at'],
694                        'month' => ['$month' => '$created_at'],
695                        'day' => ['$dayOfMonth' => '$created_at'],
696                    ],
697                    'time_saved' => ['$sum' => '$time_saved'],
698                    'cost_savings' => ['$sum' => '$cost_saved'],
699                    'characters_typed' => ['$sum' => '$characters_count'],
700                    'actions_count' => ['$sum' => 1],
701                    'actions_accepted_count' => ['$sum' => ['$cond' => [['$ne' => ['$action_type', 'autocorrect']], 1, 0]]],
702                    'actions_autocorrect_count' => ['$sum' => ['$cond' => [['$eq' => ['$action_type', 'autocorrect']], 1, 0]]],
703                ]],
704                ['$project' => [
705                    '_id' => 0,
706                    'year' => '$_id.year',
707                    'month' => '$_id.month',
708                    'day' => '$_id.day',
709                    'time_saved' => 1,
710                    'cost_savings' => 1,
711                    'characters_typed' => 1,
712                    'actions_count' => 1,
713                    'actions_accepted_count' => 1,
714                    'actions_autocorrect_count' => 1,
715                ]],
716            ]);
717        });
718
719        foreach ($actionsUsage as $data) {
720            $dt = Carbon::createFromDate($data['year'], $data['month'], $data['day']);
721            $key = $dt->toDateString();
722            if (! isset($merged[$key])) {
723                $merged[$key] = [];
724            }
725            $merged[$key]['time_saved'] = ($merged[$key]['time_saved'] ?? 0) + ($data['time_saved'] ?? 0);
726            $merged[$key]['cost_savings'] = ($merged[$key]['cost_savings'] ?? 0) + ($data['cost_savings'] ?? 0);
727            $merged[$key]['characters_typed'] = ($merged[$key]['characters_typed'] ?? 0) + ($data['characters_typed'] ?? 0);
728            $merged[$key]['fly_grammar_actions'] = $data['actions_count'] ?? 0;
729            $merged[$key]['fly_grammar_accepted'] = $data['actions_accepted_count'] ?? 0;
730            $merged[$key]['fly_grammar_autocorrect'] = $data['actions_autocorrect_count'] ?? 0;
731            $merged[$key]['fly_grammar_autocomplete'] = $data['actions_autocomplete_count'] ?? 0;
732        }
733
734        // -------- ÃšNICO BULK OP --------
735        if (! empty($merged)) {
736            FlyMsgUserDailyUsage::raw(function ($collection) use ($merged, $user_id, $email_domain, $user_status, $hubspot_id, $company_id, $group_id, $subgroup_id, $category) {
737                $bulkOps = [];
738                foreach ($merged as $key => $fields) {
739                    $dt = Carbon::parse($key); // key Ã© 'Y-m-d'
740                    // Preenche campos padrão para evitar campo unset/undefined
741                    $toUpdate = [
742                        'user_id' => $user_id,
743                        'year' => $dt->year,
744                        'month' => $dt->month,
745                        'day' => $dt->day,
746                        'email_domain' => $email_domain,
747                        'user_status' => $user_status,
748                        'hubspot_id' => $hubspot_id,
749                        'company_id' => $company_id,
750                        'group_id' => $group_id,
751                        'category' => $category,
752                        'created_at' => new UTCDateTime($dt->timestamp * 1000),
753                        'updated_at' => new UTCDateTime($dt->timestamp * 1000),
754                    ];
755
756                    if (! empty($subgroup_id)) {
757                        $toUpdate['subgroup_id'] = $subgroup_id;
758                    }
759
760                    $row = array_merge([
761                        'time_saved' => 0,
762                        'cost_savings' => 0,
763                        'characters_typed' => 0,
764                        'sentence_rewrite_count' => 0,
765                        'paragraph_rewrite_count' => 0,
766                        'flyengage_count' => 0,
767                        'flypost_count' => 0,
768                        'flycut_count' => 0,
769                        'flycuts_created' => 0,
770                        'flyplates_added' => 0,
771                        'fly_grammar_actions' => 0,
772                        'fly_grammar_accepted' => 0,
773                        'fly_grammar_autocorrect' => 0,
774                        'fly_grammar_autocomplete' => 0,
775                    ], $fields, $toUpdate);
776                    $bulkOps[] = [
777                        'updateOne' => [
778                            [
779                                'user_id' => $row['user_id'],
780                                'year' => $row['year'],
781                                'month' => $row['month'],
782                                'day' => $row['day'],
783                            ],
784                            ['$set' => $row],
785                            ['upsert' => true],
786                        ],
787                    ];
788                }
789
790                return $collection->bulkWrite($bulkOps);
791            });
792        }
793    }
794
795    private function parseMonth(int $month): string
796    {
797        return match ($month) {
798            1 => 'january',
799            2 => 'february',
800            3 => 'march',
801            4 => 'april',
802            5 => 'may',
803            6 => 'june',
804            7 => 'july',
805            8 => 'august',
806            9 => 'september',
807            10 => 'october',
808            11 => 'november',
809            default => 'december',
810        };
811    }
812
813    private function getHubspotUsage(string $user_id)
814    {
815        $allMonths = [
816            'october_2020',
817            'november_2020',
818            'december_2020',
819            'january_2021',
820            'february_2021',
821            'march_2021',
822            'april_2021',
823            'may_2021',
824            'june_2021',
825            'july_2021',
826            'august_2021',
827            'september_2021',
828            'october_2021',
829            'november_2021',
830            'december_2021',
831            'january_2022',
832            'february_2022',
833            'march_2022',
834            'april_2022',
835            'may_2022',
836            'june_2022',
837            'july_2022',
838            'august_2022',
839            'september_2022',
840            'october_2022',
841            'november_2022',
842            'december_2022',
843            'january_2023',
844        ];
845
846        $hubspotQuery = HubspotProperties::raw(function ($collection) use ($user_id, $allMonths) {
847            $fieldsProject = [
848                'flymsg_id' => 1,
849            ];
850
851            foreach ($allMonths as $month) {
852                $fieldsProject['of_characters_typed___'.$month] = 1;
853                $fieldsProject['total_cost_savings___'.$month] = 1;
854                $fieldsProject['total_time_saved___'.$month] = 1;
855            }
856
857            return $collection->aggregate([
858                ['$match' => [
859                    'flymsg_id' => $user_id,
860                ]],
861                ['$project' => $fieldsProject],
862            ]);
863        });
864
865        $doc = $hubspotQuery[0] ?? null;
866
867        $monthlyData = [];
868
869        $user = User::find($user_id);
870
871        $wagePerHour = $user->setting?->wage_per_hour ?? FlyCutUsage::WAGE_PER_HOUR;
872        $userWordPerMinute = $user->setting?->words_per_minute ?? FlyCutUsage::WORDS_PER_MINUTE;
873        $characterPerHour = $userWordPerMinute * 300;
874
875        if ($doc) {
876            foreach ($allMonths as $month) {
877                $characters = isset($doc['of_characters_typed___'.$month]) ? (int) $doc['of_characters_typed___'.$month] : 0;
878                if ($characters <= 0) {
879                    continue;
880                }
881                // $time = isset($doc['total_time_saved___'.$month]) ? (int)$doc['total_time_saved___'.$month] : 0;
882                $time = round($characters / $characterPerHour, 8);
883                // $cost = isset($doc['total_cost_savings___'.$month]) ? (float)$doc['total_cost_savings___'.$month] : 0;
884                $cost = round($time * $wagePerHour, 8);
885                $daysInMonth = cal_days_in_month(
886                    CAL_GREGORIAN,
887                    Carbon::createFromFormat('F Y', ucwords(str_replace('_', ' ', $month)))->startOfMonth()->format('m'),
888                    Carbon::createFromFormat('F Y', ucwords(str_replace('_', ' ', $month)))->startOfMonth()->format('Y')
889                );
890
891                $monthlyData[$month] = [
892                    'characters' => $characters,
893                    'characters_per_day' => (int) round($daysInMonth ? ($characters / $daysInMonth) : 0),
894                    'cost_savings' => $cost,
895                    'cost_per_day' => $daysInMonth ? ($cost / $daysInMonth) : 0,
896                    'time_saved' => $time,
897                    'time_saved_per_day' => $daysInMonth ? ($time / $daysInMonth) : 0,
898                ];
899            }
900        }
901
902        return $monthlyData;
903    }
904}