<?php

namespace App\Services;

use App\Enums\ConsultationStatus;
use App\Enums\UserType;
use App\Models\Consultation;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Support\Collection;

class AnalyticsService
{
    /**
     * Get translated month labels for chart X-axis.
     *
     * @return array<string>
     */
    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<int>
     */
    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<int>
     */
    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<float>
     */
    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<int>
     */
    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();
    }
}
