|null */ public static function forWash(Wash $wash): ?array { if (! in_array($wash->status, ['pending_start', 'running', 'active'], true)) { return null; } $wash->loadMissing('machine'); $machine = $wash->machine; $startedAt = $wash->started_at ?? $wash->created_at; $endsAt = $machine?->cycle_ends_at; if ($startedAt === null) { return [ 'percent' => 0, 'phase' => 'pending', 'phase_label' => 'En attente de démarrage', 'estimated_end_at' => $endsAt?->toIso8601String(), 'remaining_seconds' => null, ]; } $totalSeconds = $endsAt !== null ? max(1, (int) $startedAt->diffInSeconds($endsAt)) : max(1, ($wash->duration_minutes ?? 45) * 60); $elapsed = max(0, (int) $startedAt->diffInSeconds(now())); $percent = min(99, (int) round(($elapsed / $totalSeconds) * 100)); [$phase, $phaseLabel] = self::phaseForPercent($percent, $machine?->type); $remainingSeconds = $endsAt !== null ? max(0, (int) now()->diffInSeconds($endsAt, false)) : max(0, $totalSeconds - $elapsed); return [ 'percent' => $percent, 'phase' => $phase, 'phase_label' => $phaseLabel, 'estimated_end_at' => $endsAt?->toIso8601String(), 'remaining_seconds' => $remainingSeconds, ]; } /** * @return array{0: string, 1: string} */ private static function phaseForPercent(int $percent, ?string $type): array { $isDryer = str_starts_with($type ?? '', 'dryer'); if ($percent < 5) { return ['lock', 'Verrouillage']; } if ($isDryer) { if ($percent < 15) { return ['heat', 'Préchauffage']; } if ($percent < 85) { return ['dry', 'Séchage']; } return ['finish', 'Refroidissement']; } if ($percent < 15) { return ['fill', 'Remplissage']; } if ($percent < 55) { return ['wash', 'Lavage']; } if ($percent < 75) { return ['rinse', 'Rinçage']; } if ($percent < 90) { return ['spin', 'Essorage']; } return ['finish', 'Finition']; } public static function estimateDurationMinutes(?string $machineType): int { $simSeconds = (int) config('laverie.simulation.cycle_duration_seconds', 30); if ($simSeconds >= 120) { return max(1, (int) ceil($simSeconds / 60)); } return match (true) { str_starts_with($machineType ?? '', 'dryer_large') => 55, str_starts_with($machineType ?? '', 'dryer') => 45, str_starts_with($machineType ?? '', 'washer_large') => 50, default => 40, }; } }