<?php

namespace App\Filament\Tenant\Pages;

use App\Models\Tenant\Deal;
use App\Models\Tenant\Lead;
use App\Models\Tenant\Payment;
use App\Models\Tenant\WorkOrder;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;

class PipelineBoard extends Page
{
    protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-funnel';

    protected static ?string $navigationLabel = 'Pipeline';

    protected static string|\UnitEnum|null $navigationGroup = 'CRM';

    protected static ?int $navigationSort = 5;

    protected static ?string $title = 'Pipeline';

    protected string $view = 'filament.tenant.pages.pipeline-board';

    public function getMaxContentWidth(): \Filament\Support\Enums\Width
    {
        return \Filament\Support\Enums\Width::Full;
    }

    public function getHeading(): string
    {
        return '';
    }

    public function getSubheading(): ?string
    {
        return null;
    }

    public string $activeFilter = 'all';   // all | mine | urgent | today
    public ?string $openCardKey = null;    // "lead:5" / "deal:8" / "wo:12"
    public bool $showNewForm = false;      // panel in "new request" mode
    public string $searchQuery = '';
    public string $newName = '';
    public string $newPhone = '';
    public string $newCar = '';
    public string $newSource = 'call';
    public string $newNotes = '';

    public const COLUMNS = [
        'request' => ['Cerere nouă', '#94A3B8'],
        'quote' => ['Calculație', '#F59E0B'],
        'scheduled' => ['Programat', '#3B82F6'],
        'in_work' => ['În lucru', '#8B5CF6'],
        'ready' => ['Gata de ridicare', '#10B981'],
        'paid' => ['Achitat azi', '#6EE7B7'],
    ];

    public function getColumns(): array
    {
        $userId = auth()->id();
        $mineOnly = $this->activeFilter === 'mine';
        $urgentOnly = $this->activeFilter === 'urgent';
        $todayOnly = $this->activeFilter === 'today';

        // Col 1: leads (not converted) + deals at stage=new
        $leads = Lead::query()
            ->whereIn('status', ['new', 'contacted', 'no_answer'])
            ->whereNull('deal_id')
            ->when($mineOnly, fn ($q) => $q->where('assigned_to', $userId))
            ->orderByDesc('created_at')
            ->get();

        $dealQ = Deal::query()
            ->with(['client:id,name,phone', 'vehicle:id,plate,make,model', 'assignedTo:id,name'])
            ->whereNotIn('stage', ['done', 'lost'])
            ->when($mineOnly, fn ($q) => $q->where('assigned_to', $userId))
            ->when($urgentOnly, fn ($q) => $q->where('urgent', true))
            ->orderByDesc('updated_at')
            ->get();

        $woQ = WorkOrder::query()
            ->with(['client:id,name,phone', 'vehicle:id,plate,make,model', 'master:id,name'])
            ->whereNotIn('status', ['done', 'cancelled'])
            ->when($mineOnly, fn ($q) => $q->where('master_id', $userId))
            ->when($urgentOnly, fn ($q) => $q->where('urgency', '!=', 'normal'))
            ->orderBy('opened_at')
            ->get();

        $paidToday = WorkOrder::query()
            ->with(['client:id,name,phone', 'vehicle:id,plate,make,model', 'master:id,name'])
            ->where('status', 'done')
            ->where('pay_status', 'paid')
            ->whereDate('closed_at', today())
            ->when($mineOnly, fn ($q) => $q->where('master_id', $userId))
            ->orderByDesc('closed_at')
            ->get();

        $cards = [
            'request' => [],
            'quote' => [],
            'scheduled' => [],
            'in_work' => [],
            'ready' => [],
            'paid' => [],
        ];

        foreach ($leads as $lead) {
            $cards['request'][] = $this->leadCard($lead);
        }
        foreach ($dealQ as $deal) {
            $col = match ($deal->stage) {
                'new' => 'request',
                'contact', 'agree' => 'quote',
                'scheduled', 'arrived' => 'scheduled',
                'in_work' => null,  // shouldn't happen: in_work creates WO
                default => null,
            };
            if ($col) {
                $cards[$col][] = $this->dealCard($deal);
            }
        }
        foreach ($woQ as $wo) {
            $col = $wo->status === 'ready' ? 'ready' : 'in_work';
            $cards[$col][] = $this->woCard($wo);
        }
        foreach ($paidToday as $wo) {
            $cards['paid'][] = $this->woCard($wo);
        }

        // Apply search query
        $q = trim($this->searchQuery);
        if ($q !== '') {
            $needle = mb_strtolower($q);
            foreach ($cards as $col => $list) {
                $cards[$col] = array_values(array_filter($list, function ($c) use ($needle) {
                    $hay = mb_strtolower(($c['subject'] ?? '') . ' ' . ($c['client_name'] ?? '') . ' ' . ($c['plate'] ?? '') . ' ' . ($c['code'] ?? '') . ' ' . ($c['phone'] ?? ''));
                    return str_contains($hay, $needle);
                }));
            }
        }

        // Sort: urgent first, then time
        foreach ($cards as $col => $list) {
            usort($list, fn ($a, $b) => ($b['urgent'] ?? false) <=> ($a['urgent'] ?? false));
            $cards[$col] = $list;
        }

        // "Today" filter narrows further: only scheduled today OR opened today OR paid today.
        if ($todayOnly) {
            $cards['request'] = array_filter($cards['request'], fn ($c) => str_contains($c['time_text'], 'azi') || str_contains($c['time_text'], 'min'));
            // others: keep — Scheduled column inherently shows soon dates; In Work / Ready / Paid show today by default
        }

        $columns = [];
        foreach (self::COLUMNS as $key => [$label, $color]) {
            $list = array_values($cards[$key]);
            $sum = array_sum(array_map(fn ($c) => (float) $c['amount'], $list));
            $columns[$key] = [
                'label' => $label,
                'color' => $color,
                'count' => count($list),
                'sum' => $sum,
                'cards' => $list,
            ];
        }
        return $columns;
    }

    public function getStats(): array
    {
        $cols = $this->getColumns();
        $active = $cols['request']['count'] + $cols['quote']['count'] + $cols['scheduled']['count'] + $cols['in_work']['count'] + $cols['ready']['count'];
        $pipeline = $cols['request']['sum'] + $cols['quote']['sum'] + $cols['scheduled']['sum'] + $cols['in_work']['sum'] + $cols['ready']['sum'];
        $closedToday = (float) Payment::whereDate('paid_at', today())->sum('amount');
        $needAction = 0;
        foreach (['request', 'quote', 'scheduled', 'in_work', 'ready'] as $key) {
            foreach ($cols[$key]['cards'] as $card) {
                if (! empty($card['time_overdue']) || ! empty($card['urgent']) || ! empty($card['has_pending_approval'])) {
                    $needAction++;
                }
            }
        }
        $overdue = WorkOrder::whereNotIn('status', ['done', 'cancelled'])
            ->whereNotNull('eta_at')
            ->where('eta_at', '<', now())
            ->count();
        $won = Deal::whereNotNull('won_at')->where('won_at', '>=', now()->subDays(30))->count();
        $lost = Deal::whereNotNull('lost_at')->where('lost_at', '>=', now()->subDays(30))->count();
        $conversionRate = ($won + $lost) > 0 ? round(100 * $won / ($won + $lost)) : 0;

        return [
            'active' => $active,
            'pipeline_mdl' => $pipeline,
            'closed_today_mdl' => $closedToday,
            'need_action' => $needAction,
            'conversion_rate' => $conversionRate,
            'overdue' => $overdue,
        ];
    }

    public function setFilter(string $filter): void
    {
        $this->activeFilter = in_array($filter, ['all', 'mine', 'urgent', 'today'], true) ? $filter : 'all';
    }

    public function openNewForm(): void
    {
        $this->showNewForm = true;
        $this->openCardKey = null;
        $this->newName = '';
        $this->newPhone = '';
        $this->newCar = '';
        $this->newSource = 'call';
        $this->newNotes = '';
    }

    public function createNewLead(): void
    {
        $data = ['name' => trim($this->newName), 'phone' => trim($this->newPhone), 'car' => trim($this->newCar) ?: null, 'source' => $this->newSource, 'message' => trim($this->newNotes) ?: null];
        if ($data['name'] === '' || $data['phone'] === '') {
            $this->notify('Nume și telefon sunt obligatorii');
            return;
        }
        Lead::create(array_merge($data, ['status' => 'new']));
        $this->showNewForm = false;
        $this->notify('Cerere nouă adăugată');
    }

    public function exportCsv()
    {
        $columns = $this->getColumns();
        $csv = "Etapă,Cod,Subiect,Client,Telefon,Auto,Sumă,Responsabil,Stare\n";
        foreach ($columns as $col) {
            foreach ($col['cards'] as $card) {
                $csv .= sprintf(
                    "%s,%s,%s,%s,%s,%s,%.2f,%s,%s\n",
                    $col['label'],
                    $card['code'],
                    str_replace(',', ' ', $card['subject']),
                    str_replace(',', ' ', $card['client_name']),
                    $card['phone'] ?? '',
                    $card['plate'],
                    $card['amount'],
                    $card['assignee']['name'],
                    str_replace(',', ' ', $card['time_text']),
                );
            }
        }
        return response()->streamDownload(fn () => print $csv, 'pipeline-' . today()->format('Y-m-d') . '.csv', ['Content-Type' => 'text/csv']);
    }

    public function moveCard(string $key, string $toCol): void
    {
        [$kind, $id] = explode(':', $key, 2) + [null, null];
        $id = (int) $id;
        if (! $kind || ! $id || ! isset(self::COLUMNS[$toCol])) {
            return;
        }
        DB::transaction(function () use ($kind, $id, $toCol) {
            switch ($kind . '→' . $toCol) {
                // Lead in col 1, dragged to col 2 → convert to Deal at quote stage
                case "lead→quote":
                    $lead = Lead::find($id);
                    if (! $lead) return;
                    $deal = $lead->convert(['stage' => 'contact', 'quote_status' => 'sent', 'quote_sent_at' => now()]);
                    $this->notify("Lead → Deal CIU-{$deal->id} · Calculație trimisă");
                    return;

                // Lead → scheduled / in_work: convert + skip
                case "lead→scheduled":
                    $lead = Lead::find($id);
                    if (! $lead) return;
                    $deal = $lead->convert(['stage' => 'scheduled', 'scheduled_at' => now()->addDay()]);
                    $this->notify("Lead → Deal CIU-{$deal->id} · Programat");
                    return;

                case "lead→in_work":
                    $lead = Lead::find($id);
                    if (! $lead) return;
                    $deal = $lead->convert(['stage' => 'in_work']);
                    $wo = $this->createWorkOrderFromDeal($deal);
                    $this->notify("Lead → Fișă {$wo->number}");
                    return;

                // Deal in col 1/2/3 → moving across deal stages
                case "deal→request":
                    Deal::where('id', $id)->update(['stage' => 'new']);
                    return;
                case "deal→quote":
                    Deal::where('id', $id)->update([
                        'stage' => 'contact',
                        'quote_status' => 'sent',
                        'quote_sent_at' => now(),
                    ]);
                    return;
                case "deal→scheduled":
                    Deal::where('id', $id)->update([
                        'stage' => 'scheduled',
                        'scheduled_at' => Deal::find($id)?->scheduled_at ?? now()->addDay(),
                    ]);
                    return;

                // Deal → În lucru: create work order
                case "deal→in_work":
                    $deal = Deal::find($id);
                    if (! $deal) return;
                    $wo = $this->createWorkOrderFromDeal($deal);
                    $this->notify("Fișă {$wo->number} creată din deal");
                    return;

                // WO between cols
                case "wo→in_work":
                    WorkOrder::where('id', $id)->update(['status' => 'in_work']);
                    return;
                case "wo→ready":
                    WorkOrder::where('id', $id)->update(['status' => 'ready']);
                    $this->notify("Fișa marcată ca Gata de ridicare");
                    // Fire notification to client (dispatcher handles channel choice)
                    $wo = WorkOrder::find($id);
                    if ($wo) app(\App\Services\NotificationDispatcher::class)->workOrderReady($wo);
                    return;
                case "wo→paid":
                    $wo = WorkOrder::find($id);
                    if (! $wo) return;
                    $due = (float) $wo->total - (float) Payment::where('work_order_id', $wo->id)->sum('amount');
                    if ($due > 0.01) {
                        Payment::create([
                            'work_order_id' => $wo->id,
                            'client_id' => $wo->client_id,
                            'paid_at' => today(),
                            'amount' => round($due, 2),
                            'method' => 'cash',
                            'notes' => 'Achitat din Pipeline',
                        ]);
                    }
                    $wo->update(['status' => 'done', 'closed_at' => today()]);
                    $this->notify("Fișa {$wo->number} → Achitat");
                    return;
            }
        });
    }

    public function openCard(string $key): void
    {
        $this->openCardKey = $key;
    }

    /** Quick-schedule from a card: bumps the source to "Programat", creates an Appointment for tomorrow 10:00, returns calendar URL. */
    public function quickSchedule(string $key): void
    {
        [$kind, $id] = explode(':', $key, 2) + [null, null];
        $id = (int) $id;
        if (! $kind || ! $id) return;

        $clientId = null; $vehicleId = null; $dealId = null; $title = null; $masterId = null;

        if ($kind === 'lead') {
            $lead = Lead::find($id);
            if (! $lead) return;
            $deal = $lead->convert(['stage' => 'scheduled', 'scheduled_at' => now()->addDay()->setHour(10)->setMinute(0)]);
            $clientId = $deal->client_id; $vehicleId = $deal->vehicle_id; $dealId = $deal->id;
            $title = $deal->name;
        } elseif ($kind === 'deal') {
            $deal = Deal::find($id);
            if (! $deal) return;
            $deal->update(['stage' => 'scheduled', 'scheduled_at' => now()->addDay()->setHour(10)->setMinute(0)]);
            $clientId = $deal->client_id; $vehicleId = $deal->vehicle_id; $dealId = $deal->id;
            $title = $deal->name;
            $masterId = $deal->assigned_to;
        } elseif ($kind === 'wo') {
            $wo = WorkOrder::find($id);
            if (! $wo) return;
            $clientId = $wo->client_id; $vehicleId = $wo->vehicle_id;
            $title = $wo->number;
            $masterId = $wo->master_id;
        }

        \App\Models\Tenant\Appointment::create([
            'client_id' => $clientId,
            'vehicle_id' => $vehicleId,
            'master_id' => $masterId,
            'deal_id' => $dealId,
            'date' => today()->addDay(),
            'time_start' => '10:00',
            'time_end' => '11:00',
            'title' => $title ?: 'Programare',
            'status' => 'scheduled',
        ]);
        $this->notify("Programare creată · mâine 10:00");
        $this->openCardKey = null;
    }

    public function calendarUrl(): string
    {
        return route('filament.tenant.pages.calendar-board');
    }

    public function closeCard(): void
    {
        $this->openCardKey = null;
    }

    public function getOpenCardDetail(): ?array
    {
        if (! $this->openCardKey) return null;
        [$kind, $id] = explode(':', $this->openCardKey, 2) + [null, null];
        $id = (int) $id;
        if (! $kind || ! $id) return null;

        return match ($kind) {
            'lead' => $this->leadDetail(Lead::find($id)),
            'deal' => $this->dealDetail(Deal::with(['client', 'vehicle', 'assignedTo'])->find($id)),
            'wo' => $this->woDetail(WorkOrder::with(['client', 'vehicle', 'master', 'parts', 'works'])->find($id)),
            default => null,
        };
    }

    // ============== card builders ==============

    private function leadCard(Lead $lead): array
    {
        $tags = [];
        if (in_array($lead->source, ['instagram', 'facebook', 'site', 'google', 'call'])) {
            $tags[] = ['label' => Lead::SOURCES[$lead->source] ?? $lead->source, 'color' => 'gray'];
        }
        if ($lead->status === 'no_answer') {
            $tags[] = ['label' => 'Fără răspuns', 'color' => 'red'];
        }
        $diffMin = $lead->created_at?->diffInMinutes(now()) ?? 0;
        $overdue = $diffMin > 60 && $lead->status !== 'contacted';
        return [
            'kind' => 'lead',
            'id' => $lead->id,
            'key' => "lead:{$lead->id}",
            'code' => 'CR-' . str_pad((string) $lead->id, 4, '0', STR_PAD_LEFT),
            'subject' => trim(($lead->car ?: '') . ' ' . ($lead->model ?: '')) ?: $lead->name,
            'plate' => $lead->car ?: '',
            'client_name' => $lead->name ?: 'Anonim',
            'phone' => $lead->phone,
            'source' => $lead->source,
            'amount' => (float) $lead->budget,
            'urgent' => $overdue,
            'tags' => $tags,
            'time_text' => $this->humanTime($lead->created_at),
            'time_overdue' => $overdue,
            'time_icon' => 'clock',
            'assignee' => $this->assignee($lead->assignedTo),
            'progress_pct' => null,
            'has_pending_approval' => false,
            'edit_url' => route('filament.tenant.resources.leads.edit', ['record' => $lead->id]),
        ];
    }

    private function dealCard(Deal $deal): array
    {
        $tags = [];
        if ($deal->urgent) {
            $tags[] = ['label' => 'Urgent', 'color' => 'red'];
        }
        if ($deal->source && in_array($deal->source, ['instagram', 'site', 'call', 'whatsapp', 'telegram'])) {
            $tags[] = ['label' => Lead::SOURCES[$deal->source] ?? $deal->source, 'color' => 'gray'];
        }
        if ($deal->stage === 'contact' && $deal->quote_status) {
            $color = match ($deal->quote_status) {
                'sent' => 'amber',
                'seen' => 'blue',
                'responded' => 'green',
                default => 'gray',
            };
            $tags[] = ['label' => Deal::QUOTE_STATUSES[$deal->quote_status] ?? $deal->quote_status, 'color' => $color];
        }
        if (in_array($deal->stage, ['scheduled', 'arrived'])) {
            if ($deal->scheduled_at) {
                $tags[] = ['label' => $deal->scheduled_at->format('d.m · H:i'), 'color' => 'blue'];
            }
            if ($deal->bay) {
                $tags[] = ['label' => $deal->bay, 'color' => 'gray'];
            }
        }

        // Time line
        $timeText = '';
        $timeIcon = 'clock';
        $overdue = false;
        if ($deal->stage === 'contact' && $deal->quote_sent_at && in_array($deal->quote_status, ['sent', null])) {
            $mins = $deal->quote_sent_at->diffInMinutes(now());
            if ($mins > 120) {
                $overdue = true;
                $timeText = 'Trimis acum ' . $this->humanDiff($deal->quote_sent_at);
            } else {
                $timeText = 'Trimis ' . $this->humanDiff($deal->quote_sent_at);
            }
        } elseif ($deal->stage === 'contact' && $deal->quote_status === 'seen' && $deal->quote_seen_at) {
            $timeText = 'văzut ' . $this->humanDiff($deal->quote_seen_at);
        } elseif (in_array($deal->stage, ['scheduled', 'arrived']) && $deal->confirmed_at) {
            $timeText = 'Confirmat ' . (Deal::CONFIRM_CHANNELS[$deal->confirmed_via] ?? '');
            $timeIcon = 'check';
        } elseif (in_array($deal->stage, ['scheduled', 'arrived'])) {
            $timeText = 'Neconfirmat';
        } else {
            $timeText = $this->humanTime($deal->updated_at);
        }

        return [
            'kind' => 'deal',
            'id' => $deal->id,
            'key' => "deal:{$deal->id}",
            'code' => 'CIU-' . str_pad((string) $deal->id, 4, '0', STR_PAD_LEFT),
            'subject' => $deal->name,
            'plate' => $deal->vehicle?->plate ?: '',
            'client_name' => $deal->client?->name ?? '—',
            'phone' => $deal->client?->phone,
            'source' => $deal->source,
            'amount' => (float) $deal->price,
            'urgent' => (bool) $deal->urgent,
            'tags' => $tags,
            'time_text' => $timeText,
            'time_overdue' => $overdue,
            'time_icon' => $timeIcon,
            'assignee' => $this->assignee($deal->assignedTo),
            'progress_pct' => null,
            'has_pending_approval' => false,
            'edit_url' => route('filament.tenant.resources.deals.edit', ['record' => $deal->id]),
        ];
    }

    private function woCard(WorkOrder $wo): array
    {
        $tags = [];
        $tags[] = ['label' => "Fișă {$wo->number}", 'color' => 'purple'];
        if ($wo->status === 'agreement') {
            $tags[] = ['label' => 'Necesită aprobare', 'color' => 'amber'];
        }
        if ($wo->status === 'awaiting_parts') {
            $tags[] = ['label' => 'Așteaptă piese', 'color' => 'amber'];
        }
        if ($wo->status === 'ready') {
            $tags[] = ['label' => 'Gata', 'color' => 'green'];
            if ($wo->pay_status === 'partial') {
                $tags[] = ['label' => 'Avans achitat', 'color' => 'blue'];
            } elseif ($wo->pay_status !== 'paid') {
                $tags[] = ['label' => 'Neachitat', 'color' => 'amber'];
            }
        }
        if ($wo->status === 'done' && $wo->pay_status === 'paid') {
            $tags[] = ['label' => '✓ Achitat', 'color' => 'green'];
        }

        $progress = null;
        if (in_array($wo->status, ['in_work', 'diagnosis', 'agreement', 'approved', 'awaiting_parts'])) {
            $total = max(1, $wo->works()->count() + $wo->parts()->count());
            $done = $wo->works()->where('status', 'done')->count() + $wo->parts()->where('status', 'installed')->count();
            $progress = (int) round(100 * $done / $total);
        }

        $timeText = '';
        $timeIcon = 'clock';
        $overdue = false;
        if ($wo->status === 'ready') {
            $minsSinceReady = $wo->updated_at?->diffInMinutes(now()) ?? 0;
            if ($minsSinceReady > 30 && $wo->pay_status !== 'paid') {
                $overdue = true;
                $timeText = 'Notificat acum ' . $this->humanDiff($wo->updated_at);
                $timeIcon = 'phone';
            } else {
                $timeText = 'Notificat ' . $this->humanDiff($wo->updated_at);
                $timeIcon = 'message';
            }
        } elseif ($wo->eta_at) {
            $timeText = 'ETA ' . $wo->eta_at->format('H:i') . ($progress ? " · {$progress}% gata" : '');
            $overdue = $wo->eta_at->isPast();
        } else {
            $timeText = $this->humanTime($wo->opened_at);
        }

        return [
            'kind' => 'wo',
            'id' => $wo->id,
            'key' => "wo:{$wo->id}",
            'code' => $wo->number,
            'subject' => ($wo->vehicle?->make . ' ' . $wo->vehicle?->model) . ($wo->complaint ? ' — ' . str($wo->complaint)->limit(40) : ''),
            'plate' => $wo->vehicle?->plate ?: '',
            'client_name' => $wo->client?->name ?? '—',
            'phone' => $wo->client?->phone,
            'source' => null,
            'amount' => (float) $wo->total,
            'urgent' => $wo->urgency !== 'normal',
            'tags' => $tags,
            'time_text' => $timeText,
            'time_overdue' => $overdue,
            'time_icon' => $timeIcon,
            'assignee' => $this->assignee($wo->master),
            'progress_pct' => $progress,
            'has_pending_approval' => $wo->status === 'agreement',
            'edit_url' => route('filament.tenant.resources.work-orders.edit', ['record' => $wo->id]),
        ];
    }

    private function leadDetail(?Lead $lead): ?array
    {
        if (! $lead) return null;
        $card = $this->leadCard($lead);
        return array_merge($card, [
            'title' => $card['subject'] ?: ('Cerere · ' . $lead->name),
            'subtitle' => $card['code'] . ' · Cerere',
            'stages' => $this->stageStepper(0),
            'fields' => [
                'Client' => $lead->name,
                'Telefon' => $lead->phone,
                'Email' => $lead->email,
                'Automobil' => trim(($lead->car ?: '') . ' ' . ($lead->model ?: '')),
                'Sursă' => Lead::SOURCES[$lead->source] ?? $lead->source,
                'Buget estimat' => $lead->budget ? number_format($lead->budget, 0, '.', ' ') . ' MDL' : null,
            ],
            'note' => $lead->message ?? $lead->notes,
            'activity' => [],
            'wo' => null,
        ]);
    }

    private function dealDetail(?Deal $deal): ?array
    {
        if (! $deal) return null;
        $card = $this->dealCard($deal);
        $stageIdx = match ($deal->stage) {
            'new' => 0,
            'contact', 'agree' => 1,
            'scheduled', 'arrived' => 2,
            default => 0,
        };
        return array_merge($card, [
            'title' => $deal->name,
            'subtitle' => $card['code'] . ' · ' . (Deal::STAGES[$deal->stage] ?? $deal->stage),
            'stages' => $this->stageStepper($stageIdx),
            'fields' => [
                'Client' => $deal->client?->name,
                'Telefon' => $deal->client?->phone,
                'Automobil' => trim(($deal->vehicle?->make ?? '') . ' ' . ($deal->vehicle?->model ?? '') . ' · ' . ($deal->vehicle?->plate ?? '')),
                'Sursă' => $deal->source ? (Lead::SOURCES[$deal->source] ?? $deal->source) : null,
                'Responsabil' => $deal->assignedTo?->name,
                'Sumă' => number_format($deal->price, 0, '.', ' ') . ' MDL',
            ],
            'note' => $deal->note,
            'activity' => $this->loadActivity($deal),
            'wo' => null,
        ]);
    }

    private function woDetail(?WorkOrder $wo): ?array
    {
        if (! $wo) return null;
        $card = $this->woCard($wo);
        $stageIdx = match ($wo->status) {
            'new', 'diagnosis', 'agreement', 'approved' => 3,
            'in_work', 'awaiting_parts' => 3,
            'ready' => 4,
            'done' => 5,
            default => 3,
        };
        $balanceDue = (float) $wo->total - (float) Payment::where('work_order_id', $wo->id)->sum('amount');
        return array_merge($card, [
            'title' => ($wo->vehicle?->make . ' ' . $wo->vehicle?->model) . ($wo->complaint ? ' — ' . str($wo->complaint)->limit(60) : ''),
            'subtitle' => $wo->number . ' · ' . (WorkOrder::STATUSES[$wo->status] ?? $wo->status),
            'stages' => $this->stageStepper($stageIdx),
            'fields' => [
                'Client' => $wo->client?->name,
                'Telefon' => $wo->client?->phone,
                'Automobil' => trim(($wo->vehicle?->make ?? '') . ' · ' . ($wo->vehicle?->plate ?? '')),
                'Responsabil' => $wo->master?->name,
                'Sumă' => number_format($wo->total, 0, '.', ' ') . ' MDL',
                'De achitat' => number_format(max(0, $balanceDue), 0, '.', ' ') . ' MDL',
            ],
            'note' => $wo->diagnosis ?: $wo->complaint,
            'activity' => $this->loadActivity($wo),
            'wo' => [
                'number' => $wo->number,
                'status_label' => WorkOrder::STATUSES[$wo->status] ?? $wo->status,
                'progress_pct' => $card['progress_pct'],
                'eta' => $wo->eta_at?->format('H:i'),
                'has_pending_approval' => $card['has_pending_approval'],
                'tracking_url' => $wo->trackingUrl(),
            ],
        ]);
    }

    private function loadActivity($model): array
    {
        $items = [];
        if (method_exists($model, 'activities')) {
            foreach ($model->activities()->latest()->take(6)->get() as $a) {
                $items[] = [
                    'icon' => match ($a->event ?? 'updated') {
                        'created' => 'plus',
                        'deleted' => 'trash',
                        default => 'edit',
                    },
                    'color' => 'blue',
                    'text' => $a->description ?: ucfirst($a->event ?? 'actualizat'),
                    'time' => $a->created_at?->diffForHumans(),
                ];
            }
        }
        return $items;
    }

    private function stageStepper(int $currentIdx): array
    {
        $labels = ['Cerere', 'Calcul.', 'Programat', 'În lucru', 'Gata', 'Achitat'];
        $out = [];
        foreach ($labels as $i => $label) {
            $out[] = [
                'label' => $label,
                'done' => $i < $currentIdx,
                'current' => $i === $currentIdx,
            ];
        }
        return $out;
    }

    private function assignee($user): array
    {
        if (! $user) {
            return ['initials' => '?', 'name' => '—', 'color' => 'gray'];
        }
        $parts = preg_split('/\s+/', trim($user->name ?? '?'));
        $initials = strtoupper(substr($parts[0] ?? '?', 0, 1) . substr($parts[1] ?? '', 0, 1));
        // hash to a deterministic color
        $colors = ['blue', 'green', 'purple', 'amber'];
        $color = $colors[abs(crc32($user->id ?? 1)) % 4];
        return [
            'initials' => $initials ?: '?',
            'name' => $this->shortName($user->name ?? ''),
            'color' => $color,
        ];
    }

    private function shortName(string $name): string
    {
        $parts = preg_split('/\s+/', trim($name));
        if (count($parts) < 2) return $name;
        return $parts[0] . ' ' . strtoupper(substr($parts[1], 0, 1)) . '.';
    }

    private function humanTime(?Carbon $dt): string
    {
        if (! $dt) return '';
        $mins = $dt->diffInMinutes(now());
        if ($mins < 60) return "acum $mins min";
        if ($mins < 60 * 24) return "acum " . round($mins / 60) . "h";
        return $dt->format('d.m');
    }

    private function humanDiff(?Carbon $dt): string
    {
        if (! $dt) return '';
        $mins = $dt->diffInMinutes(now());
        if ($mins < 60) return "$mins min";
        if ($mins < 60 * 24) return round($mins / 60) . "h";
        return $dt->format('d.m');
    }

    private function createWorkOrderFromDeal(Deal $deal): WorkOrder
    {
        $wo = WorkOrder::create([
            'number' => WorkOrder::generateNumber($deal->company_id),
            'client_id' => $deal->client_id,
            'vehicle_id' => $deal->vehicle_id,
            'master_id' => $deal->assigned_to,
            'deal_id' => $deal->id,
            'opened_at' => today(),
            'status' => 'in_work',
            'total' => $deal->price ?: 0,
            'complaint' => $deal->note ?: $deal->name,
        ]);
        $deal->update(['stage' => 'in_work']);
        return $wo;
    }

    private function notify(string $text): void
    {
        Notification::make()->title($text)->success()->send();
    }
}
