*/ public function getMonthLabels(Carbon $startDate, int $months): array { return collect(range(0, $months - 1)) ->map(fn ($i) => $startDate->copy()->addMonths($i)->translatedFormat('M Y')) ->toArray(); } /** * Get monthly new client counts for chart data. * * @return array */ public function getMonthlyNewClients(Carbon $startDate, int $months): array { $endDate = $startDate->copy()->addMonths($months)->endOfMonth(); $data = User::query() ->whereIn('user_type', [UserType::Individual, UserType::Company]) ->whereBetween('created_at', [$startDate, $endDate]) ->get() ->groupBy(fn ($user) => $user->created_at->format('Y-m')) ->map(fn ($group) => $group->count()); return $this->fillMonthlyData($startDate, $months, $data); } /** * Get monthly consultation counts for chart data. * * @return array */ public function getMonthlyConsultations(Carbon $startDate, int $months): array { $endDate = $startDate->copy()->addMonths($months)->endOfMonth(); $data = Consultation::query() ->whereBetween('booking_date', [$startDate, $endDate]) ->get() ->groupBy(fn ($consultation) => $consultation->booking_date->format('Y-m')) ->map(fn ($group) => $group->count()); return $this->fillMonthlyData($startDate, $months, $data); } /** * Get consultation type breakdown (free vs paid). * * @return array{free: int, paid: int} */ public function getConsultationTypeBreakdown(Carbon $startDate, int $months): array { $endDate = $startDate->copy()->addMonths($months)->endOfMonth(); return [ 'free' => Consultation::query() ->whereBetween('booking_date', [$startDate, $endDate]) ->where('consultation_type', 'free') ->count(), 'paid' => Consultation::query() ->whereBetween('booking_date', [$startDate, $endDate]) ->where('consultation_type', 'paid') ->count(), ]; } /** * Get monthly no-show rates as percentages. * * @return array */ public function getMonthlyNoShowRates(Carbon $startDate, int $months): array { $results = []; for ($i = 0; $i < $months; $i++) { $monthStart = $startDate->copy()->addMonths($i)->startOfMonth(); $monthEnd = $monthStart->copy()->endOfMonth(); $total = Consultation::query() ->whereBetween('booking_date', [$monthStart, $monthEnd]) ->whereIn('status', [ConsultationStatus::Completed, ConsultationStatus::NoShow]) ->count(); $noShows = Consultation::query() ->whereBetween('booking_date', [$monthStart, $monthEnd]) ->where('status', ConsultationStatus::NoShow) ->count(); $results[] = $total > 0 ? round(($noShows / $total) * 100, 1) : 0; } return $results; } /** * Fill monthly data array ensuring all months have values. * * @return array */ private function fillMonthlyData(Carbon $startDate, int $months, Collection $data): array { return collect(range(0, $months - 1)) ->map(fn ($i) => $data->get($startDate->copy()->addMonths($i)->format('Y-m'), 0)) ->toArray(); } }