import { Multiaddr } from 'multiaddr';
import PeerId from 'peer-id';
import delay from 'delay';
import {
  isBrowser,
  isWebWorker
} from 'ipfs-utils/src/env.js';
import { expect } from 'aegir/utils/chai.js';
import {
  getDescribe,
  getIt
} from '../utils/mocha.js';
import { ipfsOptionsWebsocketsFilterAll } from '../utils/ipfs-options-websockets-filter-all.js';
export function testPeers(factory, options) {
  const ipfsOptions = ipfsOptionsWebsocketsFilterAll();
  const describe = getDescribe(options);
  const it = getIt(options);
  describe('.swarm.peers', function () {
    this.timeout(80 * 1000);
    let ipfsA;
    let ipfsB;
    let ipfsBId;
    before(async () => {
      ipfsA = (await factory.spawn({
        type: 'proc',
        ipfsOptions
      })).api;
      ipfsB = (await factory.spawn({ type: isWebWorker ? 'go' : undefined })).api;
      ipfsBId = await ipfsB.id();
      await ipfsA.swarm.connect(ipfsBId.addresses[0]);
    });
    after(() => factory.clean());
    it('should list peers this node is connected to', async () => {
      const peers = await ipfsA.swarm.peers();
      expect(peers).to.have.length.above(0);
      const peer = peers[0];
      expect(peer).to.have.a.property('addr');
      expect(Multiaddr.isMultiaddr(peer.addr)).to.equal(true);
      expect(peer).to.have.a.property('peer').that.is.a('string');
      expect(PeerId.parse(peer.peer)).to.be.ok();
      expect(peer).to.not.have.a.property('latency');
    });
    it('should list peers this node is connected to with verbose option', async () => {
      const peers = await ipfsA.swarm.peers({ verbose: true });
      expect(peers).to.have.length.above(0);
      const peer = peers[0];
      expect(peer).to.have.a.property('addr');
      expect(Multiaddr.isMultiaddr(peer.addr)).to.equal(true);
      expect(peer).to.have.a.property('peer');
      expect(peer).to.have.a.property('latency');
      expect(peer.latency).to.match(/n\/a|[0-9]+[mµ]?s/);
    });
    function getConfig(addrs) {
      addrs = Array.isArray(addrs) ? addrs : [addrs];
      return {
        Addresses: {
          Swarm: addrs,
          API: '/ip4/127.0.0.1/tcp/0',
          Gateway: '/ip4/127.0.0.1/tcp/0'
        },
        Bootstrap: [],
        Discovery: { MDNS: { Enabled: false } }
      };
    }
    it('should list peers only once', async () => {
      const nodeA = (await factory.spawn({
        type: 'proc',
        ipfsOptions
      })).api;
      const nodeB = (await factory.spawn({ type: isWebWorker ? 'go' : undefined })).api;
      const nodeBId = await nodeB.id();
      await nodeA.swarm.connect(nodeBId.addresses[0]);
      await delay(1000);
      const peersA = await nodeA.swarm.peers();
      const peersB = await nodeB.swarm.peers();
      expect(peersA).to.have.length(1);
      expect(peersB).to.have.length(1);
    });
    it('should list peers only once even if they have multiple addresses', async () => {
      const config = getConfig(isBrowser && factory.opts.type !== 'go' ? [
        `${ process.env.SIGNALA_SERVER }`,
        `${ process.env.SIGNALB_SERVER }`
      ] : [
        '/ip4/127.0.0.1/tcp/26545/ws',
        '/ip4/127.0.0.1/tcp/26546/ws'
      ]);
      const nodeA = (await factory.spawn({
        type: isBrowser && factory.opts.type === 'go' || isWebWorker ? 'js' : 'proc',
        ipfsOptions
      })).api;
      const nodeAId = await nodeA.id();
      const nodeB = (await factory.spawn({
        type: isWebWorker ? 'go' : undefined,
        ipfsOptions: { config }
      })).api;
      await nodeB.swarm.connect(nodeAId.addresses[0]);
      await delay(1000);
      const peersA = await nodeA.swarm.peers();
      const peersB = await nodeB.swarm.peers();
      expect(peersA).to.have.length(1);
      expect(peersB).to.have.length(1);
    });
  });
}