import 'package:flutter/foundation.dart'; import '../models/contact.dart'; import '../connector/meshcore_protocol.dart'; class PathHelper { static String formatPathHex(List pathBytes) { return pathBytes .map((b) => b.toRadixString(16).padLeft(2, '0').toUpperCase()) .join(','); } static String formatHopHex(List hopBytes) { return hopBytes .map((b) => b.toRadixString(16).padLeft(2, '0').toUpperCase()) .join(); } static List splitPathBytes(List pathBytes, int hashByteWidth) { if (pathBytes.isEmpty) return const []; final width = hashByteWidth.clamp(1, 4); final hops = []; for (int i = 0; i < pathBytes.length; i += width) { final endIdx = (i + width).clamp(0, pathBytes.length); final hopBytes = pathBytes.sublist(i, endIdx); if (hopBytes.isNotEmpty) { hops.add(Uint8List.fromList(hopBytes)); } } return hops; } /// Resolves path bytes to contact names, supporting multi-byte hash widths. /// Groups path bytes according to [hashByteWidth]: /// - 1: Single byte per hop (256 unique nodes) /// - 2: Two bytes per hop (65K unique nodes) /// - 3: Three bytes per hop (16M unique nodes) /// - 4: Four bytes per hop (4.3G unique nodes) static String resolvePathNames( List pathBytes, List allContacts, int hashByteWidth, ) { if (pathBytes.isEmpty) return ''; final parts = []; for (final hopBytes in splitPathBytes(pathBytes, hashByteWidth)) { final hex = formatHopHex(hopBytes); // Find matching contacts by comparing public key prefix final matches = allContacts .where((c) { if (c.publicKey.length < hopBytes.length) return false; if (c.type != advTypeRepeater && c.type != advTypeRoom) return false; // Compare bytes using listEquals for multi-byte support return listEquals( c.publicKey.sublist(0, hopBytes.length), hopBytes, ); }) .toList(); if (matches.isEmpty) { parts.add(hex); } else if (matches.length == 1) { parts.add(matches.first.name); } else { parts.add(matches.map((c) => c.name).join(' | ')); } } return parts.join(' \u2192 '); } }