increment($actorId, 'follows_made'); $this->increment($targetId, 'followers_gained'); } public function recordUnfollow(int $actorId, int $targetId): void { if (! Schema::hasTable('user_follow_analytics')) { return; } $this->increment($actorId, 'unfollows_made'); $this->increment($targetId, 'followers_lost'); } public function summaryForUser(int $userId, int $currentFollowersCount = 0): array { if (! Schema::hasTable('user_follow_analytics')) { return $this->emptySummary(); } $today = now()->toDateString(); $weekStart = now()->subDays(6)->toDateString(); $todayRow = DB::table('user_follow_analytics') ->where('user_id', $userId) ->whereDate('date', $today) ->first(); $weekly = DB::table('user_follow_analytics') ->where('user_id', $userId) ->whereBetween('date', [$weekStart, $today]) ->selectRaw('COALESCE(SUM(followers_gained), 0) as gained, COALESCE(SUM(followers_lost), 0) as lost') ->first(); $dailyGained = (int) ($todayRow->followers_gained ?? 0); $dailyLost = (int) ($todayRow->followers_lost ?? 0); $weeklyGained = (int) ($weekly->gained ?? 0); $weeklyLost = (int) ($weekly->lost ?? 0); $weeklyNet = $weeklyGained - $weeklyLost; $baseline = max(1, $currentFollowersCount - $weeklyNet); return [ 'daily' => [ 'gained' => $dailyGained, 'lost' => $dailyLost, 'net' => $dailyGained - $dailyLost, ], 'weekly' => [ 'gained' => $weeklyGained, 'lost' => $weeklyLost, 'net' => $weeklyNet, 'growth_rate' => round(($weeklyNet / $baseline) * 100, 1), ], ]; } private function increment(int $userId, string $column): void { DB::table('user_follow_analytics')->updateOrInsert( [ 'user_id' => $userId, 'date' => now()->toDateString(), ], [ $column => DB::raw("COALESCE({$column}, 0) + 1"), 'updated_at' => now(), 'created_at' => now(), ] ); } private function emptySummary(): array { return [ 'daily' => ['gained' => 0, 'lost' => 0, 'net' => 0], 'weekly' => ['gained' => 0, 'lost' => 0, 'net' => 0, 'growth_rate' => 0.0], ]; } }