import assert from 'node:assert/strict';
import { describe, test } from 'node:test';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { CondensedGraph } from '../../src/core/CondensedGraph.js';
import { ShardedSnapshotBuilder } from '../../src/core/shards/ShardedSnapshotBuilder.js';
import { ShardedSnapshot } from '../../src/core/shards/ShardedSnapshot.js';
import { FileShardStorage } from '../../src/core/shards/FileShardStorage.js';

function buildShardedSnapshot(bucketSize = 2) {
  const graph = new CondensedGraph();

  const user0 = graph._ensureNode('user:0');
  const user1 = graph._ensureNode('user:1');
  const user2 = graph._ensureNode('user:2');
  const user3 = graph._ensureNode('user:3');
  const group0 = graph._ensureNode('group:0');
  const group1 = graph._ensureNode('group:1');
  const doc0 = graph._ensureNode('doc:0');

  graph.addEdge(user0, 'member', group0);
  graph.addEdge(user3, 'member', group0);
  graph.addEdge(user2, 'member', group1);

  graph.addEdge(group0, 'viewer', doc0);
  graph.addEdge(group1, 'viewer', doc0);

  graph.addEdge(user0, 'risk', doc0, { value: 0.2, possibility: 1, reliability: 1 });
  graph.addEdge(user3, 'risk', doc0, { value: 0.9, possibility: 1, reliability: 1 });
  graph.addEdge(user2, 'risk', doc0, { value: 0.6, possibility: 1, reliability: 1 });

  graph.finalizePerfectHash();
  graph.finalizeWaveletAdjacency({ dropAdjacencyList: true });

  const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'sharded-cross-chain-'));
  const builder = new ShardedSnapshotBuilder({ bucketSize, includeDirections: ['out', 'in'] });
  const manifest = builder.build(graph, dir);
  const storage = new FileShardStorage(dir);
  const snapshot = new ShardedSnapshot(manifest, storage, { cacheLimit: 8 });
  snapshot.initializeSync();

  return { graph, snapshot, dir, ids: { user0, user1, user2, user3, group0, group1, doc0 } };
}

function collectRiskPaths(snapshot, relationIds, docId) {
  const viewerRel = relationIds.viewer;
  const memberRel = relationIds.member;
  const riskRel = relationIds.risk;

  const paths = [];
  const viewerEdges = snapshot.executeGetInEdgesSync(docId, viewerRel, new Set()) || [];
  for (const viewer of viewerEdges) {
    const groupId = viewer.src;
    const memberEdges = snapshot.executeGetInEdgesSync(groupId, memberRel, new Set()) || [];
    for (const member of memberEdges) {
      const userId = member.src;
      const riskEdge = snapshot.executeFindEdgeSync(userId, riskRel, docId, new Set());
      if (riskEdge) {
        paths.push({ userId, docId });
      }
    }
  }
  return paths;
}

// ADR-003: sharded snapshots are stubs in src/core/shards/ — tests are the spec for when the subsystem is implemented.
describe.skip('Sharded snapshot cross-chain aggregation', () => {
  test('aggregates risk values across userset paths', () => {
    const { graph, snapshot, dir, ids } = buildShardedSnapshot(2);
    const relationIds = {
      member: graph.getRelationId('member'),
      viewer: graph.getRelationId('viewer'),
      risk: graph.getRelationId('risk')
    };

    const plan = new Set();
    snapshot.planInEdges(relationIds.viewer, ids.doc0, plan);
    snapshot.planInEdges(relationIds.member, ids.group0, plan);
    snapshot.planInEdges(relationIds.member, ids.group1, plan);
    snapshot.planOutEdges(relationIds.risk, ids.user0, plan);
    snapshot.planOutEdges(relationIds.risk, ids.user2, plan);
    snapshot.planOutEdges(relationIds.risk, ids.user3, plan);
    snapshot.prefetchPlanSync(plan);

    const paths = collectRiskPaths(snapshot, relationIds, ids.doc0);
    assert.strictEqual(paths.length, 3);

    fs.rmSync(dir, { recursive: true, force: true });
  });

  test('cross-bucket paths resolve with inbound and outbound shards', () => {
    const { graph, snapshot, dir, ids } = buildShardedSnapshot(2);
    const relationIds = {
      member: graph.getRelationId('member'),
      viewer: graph.getRelationId('viewer'),
      risk: graph.getRelationId('risk')
    };

    const plan = new Set();
    snapshot.planInEdges(relationIds.viewer, ids.doc0, plan);
    snapshot.planInEdges(relationIds.member, ids.group0, plan);
    snapshot.planInEdges(relationIds.member, ids.group1, plan);
    snapshot.planOutEdges(relationIds.risk, ids.user0, plan);
    snapshot.planOutEdges(relationIds.risk, ids.user2, plan);
    snapshot.planOutEdges(relationIds.risk, ids.user3, plan);
    snapshot.prefetchPlanSync(plan);

    const paths = collectRiskPaths(snapshot, relationIds, ids.doc0);
    assert.strictEqual(paths.length, 3);

    fs.rmSync(dir, { recursive: true, force: true });
  });
});
