<?php

namespace App\Support;

use App\Models\Area;
use App\Models\User;
use Illuminate\Support\Collection;

/**
 * Lista y resuelve qué usuario registra un escaneo (estación compartida / recepción).
 */
final class LaundryScanOperatorResolver
{
    public static function sessionCanDelegate(User $session): bool
    {
        if ($session->hasRole('Administrador')) {
            return true;
        }

        return $session->can('lavanderia.recepcion');
    }

    /**
     * @return Collection<int, User>
     */
    public static function eligibleForArea(Area $area): Collection
    {
        return User::query()
            ->where('estatus', 'activo')
            ->with(['roles', 'area'])
            ->orderBy('name')
            ->get()
            ->filter(fn (User $user) => self::canRegisterScan($user, $area))
            ->values();
    }

    public static function canRegisterScan(User $user, Area $area): bool
    {
        if (! AreaPermission::canOperate($user, $area)) {
            return false;
        }

        return UserAreaAssignment::scanDeniedMessage($user, $area) === null;
    }

    /**
     * @return array{ok: true, user: User}|array{ok: false, status: int, message: string, errors?: array<string, array<int, string>>}
     */
    public static function resolve(User $session, Area $area, ?int $operatorUserId): array
    {
        if ($operatorUserId === null) {
            if (! self::canRegisterScan($session, $area)) {
                $assignMsg = UserAreaAssignment::scanDeniedMessage($session, $area);

                return [
                    'ok' => false,
                    'status' => 403,
                    'message' => $assignMsg ?? 'No puede escanear en esta área.',
                    'errors' => ['area_code' => [$assignMsg ?? 'Operación no autorizada para el área seleccionada.']],
                ];
            }

            return ['ok' => true, 'user' => $session];
        }

        $operator = User::query()
            ->whereKey($operatorUserId)
            ->where('estatus', 'activo')
            ->with(['roles', 'area'])
            ->first();

        if ($operator === null) {
            return [
                'ok' => false,
                'status' => 422,
                'message' => 'Operador no válido.',
                'errors' => ['operator_user_id' => ['El usuario seleccionado no existe o está inactivo.']],
            ];
        }

        if ((int) $operator->id !== (int) $session->id && ! self::sessionCanDelegate($session)) {
            return [
                'ok' => false,
                'status' => 403,
                'message' => 'No puede registrar escaneos a nombre de otro operador.',
                'errors' => ['operator_user_id' => ['Solo recepción o administración pueden elegir otro operador.']],
            ];
        }

        if (! self::canRegisterScan($operator, $area)) {
            return [
                'ok' => false,
                'status' => 403,
                'message' => 'El operador seleccionado no puede escanear en esta área.',
                'errors' => ['operator_user_id' => ['Revise el área asignada y los permisos del operador.']],
            ];
        }

        return ['ok' => true, 'user' => $operator];
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    public static function toListPayload(Collection $users): array
    {
        return $users->map(fn (User $u) => [
            'id' => $u->id,
            'name' => $u->name,
            'email' => $u->email,
            'area_id' => $u->area_id,
            'area' => $u->area ? [
                'id' => $u->area->id,
                'code' => $u->area->code,
                'name' => $u->area->name,
            ] : null,
            'roles' => $u->roles->pluck('name')->values()->all(),
        ])->all();
    }
}
