<?php

namespace App\Services\Care\Ambulance;

use App\Models\Organization;
use App\Models\Visit;
use App\Services\Care\SpecialtyShellService;
use Illuminate\Support\Collection;

/**
 * Stage-grouped EMS dispatch board (replaces Call next queue home for ambulance).
 */
class AmbulanceDispatchBoardService
{
    public function __construct(
        protected SpecialtyShellService $shell,
    ) {}

    /**
     * @param  list<int>|null  $practitionerScope
     * @return array{
     *     columns: list<array{
     *         key: string,
     *         label: string,
     *         count: int,
     *         items: Collection<int, Visit>,
     *         empty: string,
     *         accent: string,
     *         dot: string,
     *         next_stage: ?string,
     *         next_label: ?string
     *     }>,
     *     active_count: int,
     *     completed_today: int
     * }
     */
    public function board(
        Organization $organization,
        string $ownerRef,
        ?int $branchScope = null,
        ?array $practitionerScope = null,
    ): array {
        $flow = app(AmbulanceWorkflowService::class)->stageFlow();
        $open = $this->shell->openVisits($organization, 'ambulance', $ownerRef, $branchScope, $practitionerScope, 80);
        $completed = $this->completedToday($organization, $ownerRef, $branchScope, $practitionerScope);

        $byStage = [
            AmbulanceWorkflowService::STAGE_CHECK_IN => collect(),
            AmbulanceWorkflowService::STAGE_DISPATCH => collect(),
            AmbulanceWorkflowService::STAGE_ON_SCENE => collect(),
            AmbulanceWorkflowService::STAGE_TRANSPORT => collect(),
            AmbulanceWorkflowService::STAGE_HANDOVER => collect(),
            AmbulanceWorkflowService::STAGE_COMPLETED => $completed,
        ];

        foreach ($open as $visit) {
            $stage = $visit->specialty_stage;
            if ($stage === null || $stage === '' || $stage === AmbulanceWorkflowService::STAGE_CHECK_IN) {
                $byStage[AmbulanceWorkflowService::STAGE_CHECK_IN]->push($visit);
            } elseif (isset($byStage[$stage]) && $stage !== AmbulanceWorkflowService::STAGE_COMPLETED) {
                $byStage[$stage]->push($visit);
            } else {
                // Unknown / unexpected stage — keep visible under New call.
                $byStage[AmbulanceWorkflowService::STAGE_CHECK_IN]->push($visit);
            }
        }

        $meta = [
            AmbulanceWorkflowService::STAGE_CHECK_IN => [
                'label' => 'New call',
                'empty' => 'No new calls.',
                'accent' => 'text-amber-700',
                'dot' => 'bg-amber-500',
            ],
            AmbulanceWorkflowService::STAGE_DISPATCH => [
                'label' => 'Dispatched',
                'empty' => 'Nothing dispatched.',
                'accent' => 'text-indigo-700',
                'dot' => 'bg-indigo-500',
            ],
            AmbulanceWorkflowService::STAGE_ON_SCENE => [
                'label' => 'On scene',
                'empty' => 'No crews on scene.',
                'accent' => 'text-sky-700',
                'dot' => 'bg-sky-500',
            ],
            AmbulanceWorkflowService::STAGE_TRANSPORT => [
                'label' => 'Transport',
                'empty' => 'No patients in transport.',
                'accent' => 'text-violet-700',
                'dot' => 'bg-violet-500',
            ],
            AmbulanceWorkflowService::STAGE_HANDOVER => [
                'label' => 'Handover',
                'empty' => 'No handovers in progress.',
                'accent' => 'text-emerald-700',
                'dot' => 'bg-emerald-500',
            ],
            AmbulanceWorkflowService::STAGE_COMPLETED => [
                'label' => 'Completed today',
                'empty' => 'None completed today.',
                'accent' => 'text-slate-500',
                'dot' => 'bg-slate-300',
            ],
        ];

        $columns = [];
        foreach ($meta as $key => $column) {
            $items = $byStage[$key] ?? collect();
            $next = $flow[$key]['next'] ?? null;
            $nextLabel = $flow[$key]['label'] ?? null;
            if ($key === AmbulanceWorkflowService::STAGE_COMPLETED) {
                $next = null;
                $nextLabel = null;
            }

            $columns[] = [
                'key' => $key,
                'label' => $column['label'],
                'count' => $items->count(),
                'items' => $items,
                'empty' => $column['empty'],
                'accent' => $column['accent'],
                'dot' => $column['dot'],
                'next_stage' => $next !== $key ? $next : null,
                'next_label' => $next !== $key ? $nextLabel : null,
            ];
        }

        $activeCount = collect($columns)
            ->reject(fn (array $col) => $col['key'] === AmbulanceWorkflowService::STAGE_COMPLETED)
            ->sum('count');

        return [
            'columns' => $columns,
            'active_count' => $activeCount,
            'completed_today' => $completed->count(),
        ];
    }

    /**
     * @param  list<int>|null  $practitionerScope
     * @return Collection<int, Visit>
     */
    protected function completedToday(
        Organization $organization,
        string $ownerRef,
        ?int $branchScope = null,
        ?array $practitionerScope = null,
        int $limit = 40,
    ): Collection {
        $departmentIds = $this->shell->departmentIds($organization, 'ambulance', $ownerRef, $branchScope);

        return Visit::owned($ownerRef)
            ->where('organization_id', $organization->id)
            ->where(function ($q) {
                $q->where('specialty_stage', AmbulanceWorkflowService::STAGE_COMPLETED)
                    ->orWhere(function ($qq) {
                        $qq->where('status', Visit::STATUS_COMPLETED)
                            ->whereDate('completed_at', today());
                    });
            })
            ->where(function ($q) {
                $q->whereDate('completed_at', today())
                    ->orWhere(function ($qq) {
                        $qq->whereNull('completed_at')
                            ->whereDate('updated_at', today());
                    });
            })
            ->when($branchScope, fn ($q) => $q->where('branch_id', $branchScope))
            ->whereHas('appointment', function ($q) use ($departmentIds, $practitionerScope) {
                $q->when($departmentIds !== [], fn ($qq) => $qq->whereIn('department_id', $departmentIds))
                    ->when($departmentIds === [], fn ($qq) => $qq->whereRaw('1 = 0'))
                    ->when(
                        $practitionerScope !== null,
                        fn ($qq) => $qq->whereIn('practitioner_id', $practitionerScope ?: [0]),
                    );
            })
            ->with(['patient', 'appointment.practitioner', 'appointment.department'])
            ->orderByDesc('completed_at')
            ->orderByDesc('id')
            ->limit($limit)
            ->get();
    }
}
