<?php

namespace App\Domain\Shared\Services;

use App\Domain\Attendance\Enums\AttendanceStatus;
use App\Domain\Attendance\Models\AttendanceRecord;
use App\Domain\Financial\Models\Invoice;
use App\Domain\Financial\Models\Payment;
use App\Domain\Participant\Models\Participant;
use App\Domain\POS\Models\POSTransaction;
use App\Domain\Training\Models\Enrollment;
use Illuminate\Support\Facades\DB;

class ReportService
{
    public function financialSummary(string $from, string $to, ?int $branchId = null): array
    {
        return [
            'total_invoiced' => Invoice::whereBetween('created_at', [$from, $to])
                ->when($branchId, fn ($q) => $q->whereHasMorph('billable', [Participant::class], fn ($p) => $p->where('branch_id', $branchId)))->sum('total_amount'),
            'total_collected' => Payment::where('status', 'confirmed')
                ->whereBetween('created_at', [$from, $to])
                ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->sum('amount'),
            'total_outstanding' => Invoice::whereIn('status', ['sent', 'partially_paid', 'overdue'])
                ->when($branchId, fn ($q) => $q->whereHasMorph('billable', [Participant::class], fn ($p) => $p->where('branch_id', $branchId)))->sum('due_amount'),
            'pos_revenue' => POSTransaction::whereBetween('processed_at', [$from, $to])
                ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->sum('total_amount'),
            'payment_methods' => Payment::where('status', 'confirmed')
                ->whereBetween('created_at', [$from, $to])
                ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
                ->select('method', DB::raw('SUM(amount) as total'), DB::raw('COUNT(*) as count'))
                ->groupBy('method')
                ->get()->toArray(),
        ];
    }

    public function attendanceReport(string $from, string $to, ?int $groupId = null, ?int $branchId = null): array
    {
        $query = AttendanceRecord::whereBetween('created_at', [$from, $to]);
        if ($groupId) {
            $query->whereHas('session', fn ($q) => $q->where('training_group_id', $groupId));
        } elseif ($branchId) {
            $query->whereHas('session.group', fn ($q) => $q->where('branch_id', $branchId));
        }

        $total = (clone $query)->count();
        $excluded = (clone $query)->whereIn('status', [AttendanceStatus::Cancelled, AttendanceStatus::Exempt])->count();
        $positive = (clone $query)->whereIn('status', [AttendanceStatus::Present, AttendanceStatus::Late, AttendanceStatus::Partial])->count();
        $denominator = $total - $excluded;

        return [
            'total_records' => $total,
            'present' => (clone $query)->where('status', AttendanceStatus::Present)->count(),
            'late' => (clone $query)->where('status', AttendanceStatus::Late)->count(),
            'absent' => (clone $query)->where('status', AttendanceStatus::Absent)->count(),
            'excused' => (clone $query)->where('status', AttendanceStatus::Excused)->count(),
            'rate' => $denominator > 0 ? round(($positive / $denominator) * 100, 1) : 0,
        ];
    }

    public function enrollmentReport(string $from, string $to, ?int $branchId = null): array
    {
        return [
            'new_enrollments' => Enrollment::whereBetween('enrollment_date', [$from, $to])
                ->when($branchId, fn ($q) => $q->whereHas('group', fn ($g) => $g->where('branch_id', $branchId)))->count(),
            'by_status' => Enrollment::whereBetween('enrollment_date', [$from, $to])
                ->when($branchId, fn ($q) => $q->whereHas('group', fn ($g) => $g->where('branch_id', $branchId)))
                ->select('status', DB::raw('COUNT(*) as count'))
                ->groupBy('status')
                ->pluck('count', 'status')->toArray(),
            'active_participants' => Participant::where('status', 'active')
                ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->count(),
            'by_membership_type' => Participant::where('status', 'active')
                ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
                ->whereNotNull('membership_type')
                ->select('membership_type', DB::raw('COUNT(*) as count'))
                ->groupBy('membership_type')
                ->pluck('count', 'membership_type')->toArray(),
        ];
    }

    public function participantList(array $filters = []): \Illuminate\Support\Collection
    {
        $query = Participant::with(['person', 'enrollments.group'])
            ->when($filters['status'] ?? null, fn ($q, $s) => $q->where('status', $s))
            ->when($filters['branch_id'] ?? null, fn ($q, $b) => $q->where('branch_id', $b))
            ->when($filters['group_id'] ?? null, fn ($q, $g) => $q->whereHas(
                'enrollments',
                fn ($eq) => $eq->where('training_group_id', $g)->where('status', 'active')
            ));

        return $query->get()->map(fn ($p) => [
            'name' => $p->person?->name_ar,
            'phone' => $p->person?->phone,
            'status' => $p->status,
            'membership_type' => $p->membership_type ?? 'regular',
            'active_groups' => $p->enrollments->where('status', 'active')
                ->map(fn ($e) => $e->group?->name_ar)->filter()->implode(', '),
            'joined_at' => $p->created_at?->format('Y-m-d'),
        ]);
    }
}
