id; // Verificar si está en Redis $enRedis = Redis::get($key); if ($enRedis) { // Ya está marcado como robado, verificar si sigue así $resultado = $this->verificarVehiculoRobado($fastId, json_decode($enRedis, true)); $this->registrarDeteccion($fastId, $resultado, $arcoId, $antena); return $resultado; } // No está en Redis, consultar servicios $resultado = $this->consultarNuevoVehiculo($fastId); $this->registrarDeteccion($fastId, $resultado, $arcoId, $antena); return $resultado; } /** * Consultar vehículo por tag_id, placa o VIN */ public function consultarVehiculoPorTag(string $fastId) { try { $vehiculoExterno = $this->consultaRepuveCons->consultarVehiculoPorTag($fastId); if ($vehiculoExterno) { Log::info('VehicleService: Vehículo encontrado', [ 'fast_id' => $fastId, 'tag_number' => $vehiculoExterno['tag_number'] ?? null, 'placa' => $vehiculoExterno['placa'] ?? null, 'vin' => $vehiculoExterno['vin'] ?? null ]); } else { Log::info('VehicleService: Vehículo no encontrado', [ 'fast_id' => $fastId ]); } return $vehiculoExterno; } catch (\Exception $e) { Log::error('VehicleService: Error en consulta', [ 'fast_id' => $fastId, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return null; } } /** * Listar todos los vehículos robados activos en Redis */ public function listarVehiculosRobados(): array { $keys = Redis::keys('vehiculo:robado:*'); $vehiculos = []; foreach ($keys as $key) { $datos = Redis::get($key); if ($datos) { $vehiculos[] = json_decode($datos, true); } } return $vehiculos; } /** * Listar todas las detecciones del día desde Redis * @param string|null $fecha Fecha en formato Y-m-d (opcional, por defecto hoy) * @return array */ public function listarDeteccionesDelDia(?string $fecha = null): array { $fecha = $fecha ?? now()->format('Y-m-d'); $pattern = "deteccion:dia:{$fecha}:*"; $keys = Redis::keys($pattern); $detecciones = []; foreach ($keys as $key) { $datos = Redis::get($key); if ($datos) { $detecciones[] = json_decode($datos, true); } } // Ordenar por fecha de detección (más reciente primero) usort($detecciones, function($a, $b) { return strcmp($b['fecha_deteccion'], $a['fecha_deteccion']); }); return $detecciones; } /** * Obtener estadísticas de detecciones del día * @param string|null $fecha Fecha en formato Y-m-d (opcional, por defecto hoy) * @return array */ public function obtenerEstadisticasDelDia(?string $fecha = null): array { $detecciones = $this->listarDeteccionesDelDia($fecha); $total = count($detecciones); $robados = collect($detecciones)->where('tiene_reporte_robo', true)->count(); $libres = collect($detecciones)->where('tiene_reporte_robo', false)->count(); return [ 'fecha' => $fecha ?? now()->format('Y-m-d'), 'total_detecciones' => $total, 'vehiculos_robados' => $robados, 'vehiculos_libres' => $libres, 'detecciones' => $detecciones ]; } /** * Listar detecciones del día de un arco específico */ public function listarDeteccionesDelDiaPorArco(int $arcoId, ?string $fecha = null): array { $todasDetecciones = $this->listarDeteccionesDelDia($fecha); // Filtrar solo las detecciones de este arco $deteccionesArco = collect($todasDetecciones) ->where('arco_id', $arcoId) ->values() ->all(); return $deteccionesArco; } /** * Consultar nuevo vehículo (no está en Redis de robados) */ private function consultarNuevoVehiculo(string $fastId): array { // Consultar con FastID (tag_number) $datosVehiculo = $this->consultaRepuveCons->consultarVehiculoPorTag($fastId); if (!$datosVehiculo || !$datosVehiculo['vin']) { Log::warning('Vehículo NO encontrado.', [ 'fast_id' => $fastId ]); return [ 'success' => false, 'message' => 'No se encontró información del vehículo.' ]; } Log::info('Vehículo detectado - LIBRE (no está en Redis de robados)', [ 'fast_id' => $fastId, 'vin' => $datosVehiculo['vin'], 'placa' => $datosVehiculo['placa'] ]); return [ 'success' => true, 'tiene_reporte_robo' => false, 'estado' => 'LIBRE', 'vehiculo' => $datosVehiculo ]; } /** * Verificar vehículo robado (ya está en Redis) */ private function verificarVehiculoRobado(string $fastId, array $datosRedis): array { $this->actualizarDeteccionRedis($fastId, $datosRedis); Log::warning('Vehículo robado detectado nuevamente', [ 'fast_id' => $fastId, 'vin' => $datosRedis['vin'] ?? null, 'placa' => $datosRedis['placa'] ?? null, 'detecciones' => ($datosRedis['detecciones'] ?? 0) + 1 ]); return [ 'success' => true, 'tiene_reporte_robo' => true, 'estado' => 'ROBADO', 'accion' => 'ACTUALIZADO_EN_REDIS', 'vehiculo' => $datosRedis ]; } /** * Actualizar contador de detecciones en Redis */ private function actualizarDeteccionRedis(string $fastId, array $datosActuales) { $key = "vehiculo:robado:{$fastId}"; $datosActuales['ultima_deteccion'] = now()->toIso8601String(); $datosActuales['detecciones'] = ($datosActuales['detecciones'] ?? 0) + 1; Redis::set($key, json_encode($datosActuales)); } /** * Registrar detección en MySQL y Redis (detecciones del día) */ private function registrarDeteccion(string $fastId, array $resultado, ?int $arcoId = null, ?string $antena = null) { // Datos mínimos que siempre tenemos $datosMinimos = [ 'arco_id' => $arcoId, 'antena' => $antena, 'fast_id' => $fastId, 'fecha_deteccion' => now() ]; // Si encontramos el vehículo, agregamos datos completos if ($resultado['success'] && isset($resultado['vehiculo'])) { $vehiculo = $resultado['vehiculo']; Detection::create(array_merge($datosMinimos, [ 'vin' => $vehiculo['vin'] ?? null, 'placa' => $vehiculo['placa'] ?? null, 'marca' => $vehiculo['marca'] ?? null, 'modelo' => $vehiculo['modelo'] ?? null, 'color' => $vehiculo['color'] ?? null, ])); // También registrar en Redis (detecciones del día) $this->registrarDeteccionDelDia($fastId, $vehiculo, $arcoId, $resultado, $antena); } else { // No encontrado: guardar solo datos mínimos Detection::create(array_merge($datosMinimos, [ 'vin' => null, 'placa' => null, 'marca' => null, 'modelo' => null, 'color' => null, ])); // Registrar en Redis con datos incompletos $this->registrarDeteccionDelDia($fastId, [], $arcoId, [ 'estado' => 'DESCONOCIDO', 'tiene_reporte_robo' => false ], $antena); } } /** * Registrar detección en Redis para el día actual * Formato de key: deteccion:dia:YYYY-MM-DD:{fastId}:{timestamp} * Expira automáticamente a las 23:59:59 del día */ private function registrarDeteccionDelDia(string $fastId, array $vehiculo, ?int $arcoId, array $resultado, ?string $antena = null) { $fecha = now()->format('Y-m-d'); $timestamp = now()->timestamp; $key = "deteccion:dia:{$fecha}:{$fastId}:{$timestamp}"; $datosDeteccion = [ 'fast_id' => $fastId, 'vin' => $vehiculo['vin'] ?? null, 'placa' => $vehiculo['placa'] ?? null, 'marca' => $vehiculo['marca'] ?? null, 'modelo' => $vehiculo['modelo'] ?? null, 'color' => $vehiculo['color'] ?? null, 'arco_id' => $arcoId, 'antena' => $antena, 'estado' => $resultado['estado'] ?? 'LIBRE', 'tiene_reporte_robo' => $resultado['tiene_reporte_robo'] ?? false, 'fecha_deteccion' => now()->toIso8601String(), ]; // Guardar en Redis Redis::set($key, json_encode($datosDeteccion)); // Calcular segundos hasta el final del día (23:59:59) $finDelDia = now()->endOfDay(); $segundosHastaFinDelDia = $finDelDia->timestamp - now()->timestamp; // Establecer expiración automática al final del día Redis::expire($key, $segundosHastaFinDelDia); } }