build static method

MerkleTree build(
  1. List<MapEntry<String, String>> items
)

Builds a Merkle Tree from a map of HLC strings to content hashes.

Implementation

static MerkleTree build(List<MapEntry<String, String>> items) {
  // 1. Group items by Hour prefix (length 13: YYYY-MM-DDTHH)
  final Map<String, List<String>> hourBuckets = {};

  for (final entry in items) {
    final hlcStr = entry.key;
    final contentHash = entry.value;

    // Extract ISO prefix "YYYY-MM-DDTHH:mm" (16 chars)
    // If invalid or too short, bucket into a default "0000-00-00T00:00"
    String minutePrefix = '0000-00-00T00:00';
    if (hlcStr.length >= 16 && hlcStr.contains('T') && hlcStr.contains(':')) {
      minutePrefix = hlcStr.substring(0, 16);
    }

    hourBuckets.putIfAbsent(minutePrefix, () => []).add(contentHash);
  }

  // 2. Build Hour Nodes (Leaves of the bucket tree)
  final Map<String, MerkleNode> hourNodes = {};
  for (final entry in hourBuckets.entries) {
    final prefix = entry.key;
    final hashes = entry.value;
    hourNodes[prefix] = MerkleNode(
      hash: combineHashes(hashes),
      prefix: prefix,
      count: hashes.length,
    );
  }

  // 3. Group Hour Nodes by Day prefix (length 10: YYYY-MM-DD)
  final Map<String, Map<String, MerkleNode>> dayBuckets = {};
  for (final entry in hourNodes.entries) {
    final hourPrefix = entry.key;
    final node = entry.value;

    String dayPrefix = '0000-00-00';
    if (hourPrefix.length >= 10) {
      dayPrefix = hourPrefix.substring(0, 10);
    }

    dayBuckets.putIfAbsent(dayPrefix, () => {})[hourPrefix] = node;
  }

  // 4. Build Day Nodes
  final Map<String, MerkleNode> dayNodes = {};
  for (final entry in dayBuckets.entries) {
    final prefix = entry.key;
    final children = entry.value;
    final childHashes = children.values.map((n) => n.hash).toList();
    final count = children.values.fold(0, (sum, n) => sum + n.count);

    dayNodes[prefix] = MerkleNode(
      hash: combineHashes(childHashes),
      prefix: prefix,
      children: children,
      count: count,
    );
  }

  // 5. Build Root Node
  final rootChildHashes = dayNodes.values.map((n) => n.hash).toList();
  final totalCount = dayNodes.values.fold(0, (sum, n) => sum + n.count);

  final rootNode = MerkleNode(
    hash: combineHashes(rootChildHashes),
    prefix: '',
    children: dayNodes,
    count: totalCount,
  );

  return MerkleTree(rootNode);
}