min(20, collect([$lead->email, $lead->company, $lead->city, $lead->product_interest])->filter()->count() * 5), 'priority' => min(20, max(0, (int) $lead->priority) * 5), 'engagement' => min(30, $lead->calls()->count() * 5 + $lead->followUps()->whereNotNull('completed_at')->count() * 5), 'recency' => $lead->last_call_at?->gte(now()->subDays(7)) ? 15 : 0, 'intent' => in_array($lead->interest_level, ['high', 'very_high'], true) ? 15 : ($lead->interest_level === 'medium' ? 8 : 0), ]; $score = min(100, array_sum($breakdown)); $level = $score >= 70 ? 'hot' : ($score >= 40 ? 'warm' : 'cold'); $lead->update(['lead_score' => $score, 'score_level' => $level, 'score_breakdown' => $breakdown, 'scored_at' => now()]); ActivityLogger::log('lead_scored', "Lead {$lead->id} scored {$score}", $lead, null, ['score' => $score, 'level' => $level]); $this->automations->dispatch('lead_scored', $lead, "lead-score:{$lead->id}:{$lead->scored_at?->timestamp}", ['score' => $score, 'score_level' => $level]); return $lead->fresh(); } }