const { eq, ok, notOk } = require('../../helpers/assert');
const { makeNetwork, makePeer } = require('../../helpers/setup');

describe('blockchain (blockexplorer)', (t) => {
  t('member sees decrypted tribe content', async () => {
    const net = makeNetwork(); const A = makePeer(net); A.setActor();
    const r = await A.use('tribes').createTribe('G', '', null, '', [], true, 'strict', null, 'OPEN', '');
    await A.use('tribesContent').create(r.key, 'feed', { description: 'hi' });
    const blocks = await A.use('blockchain').listBlockchain('all', A.keypair.id, {});
    ok(Array.isArray(blocks));
    const ours = blocks.find(b => b.content && b.content.description === 'hi');
    ok(ours);
    eq(ours.content._decrypted, true);
  });

  t('non-member sees no decrypted tribe content', async () => {
    const net = makeNetwork(); const A = makePeer(net); const B = makePeer(net); A.setActor();
    const r = await A.use('tribes').createTribe('G', '', null, '', [], true, 'strict', null, 'OPEN', '');
    await A.use('tribesContent').create(r.key, 'feed', { description: 'top secret' });
    B.setActor();
    const blocks = await B.use('blockchain').listBlockchain('all', B.keypair.id, {});
    const leaked = blocks.find(b => b.content && b.content.description === 'top secret');
    notOk(leaked);
  });

  t('hidden envelope types do not appear in blockexplorer', async () => {
    const net = makeNetwork(); const A = makePeer(net); A.setActor();
    const r = await A.use('tribes').createTribe('T', '', null, '', [], true, 'strict', null, 'OPEN', '');
    await A.use('tribes').generateInvite(r.key);
    const blocks = await A.use('blockchain').listBlockchain('all', A.keypair.id, {});
    const inviteMsg = blocks.find(b => b.type === 'tribe-invite-msg');
    notOk(inviteMsg);
  });
});

describe('blockchain: computeStats (explorer stats panel)', (t) => {
  const { computeStats } = require('../../../src/views/blockchain_view');

  t('empty input returns zero totals', () => {
    const s = computeStats([]);
    eq(s.total, 0);
    eq(s.typeBreakdown.length, 0);
    eq(s.topAuthors.length, 0);
  });

  t('counts by type and sorts descending', () => {
    const blocks = [
      { type: 'forum', author: '@a' },
      { type: 'forum', author: '@b' },
      { type: 'forum', author: '@a' },
      { type: 'post',  author: '@a' },
      { type: 'vote',  author: '@c' }
    ];
    const s = computeStats(blocks);
    eq(s.total, 5);
    eq(s.typeBreakdown[0].type, 'forum');
    eq(s.typeBreakdown[0].count, 3);
    eq(s.typeBreakdown[1].count, 1);
  });

  t('topAuthors caps at 5 and ranks correctly', () => {
    const blocks = [];
    for (let i = 0; i < 10; i++) blocks.push({ type: 'post', author: '@a' });
    for (let i = 0; i < 5; i++)  blocks.push({ type: 'post', author: '@b' });
    for (let i = 0; i < 3; i++)  blocks.push({ type: 'post', author: '@c' });
    blocks.push({ type: 'post', author: '@d' });
    blocks.push({ type: 'post', author: '@e' });
    blocks.push({ type: 'post', author: '@f' });
    const s = computeStats(blocks);
    eq(s.topAuthors.length, 5);
    eq(s.topAuthors[0].author, '@a');
    eq(s.topAuthors[0].count, 10);
    eq(s.topAuthors[1].author, '@b');
    eq(s.topAuthors[2].author, '@c');
    notOk(s.topAuthors.find(a => a.author === '@f'), 'overflow author excluded');
  });

  t('ignores entries with missing type', () => {
    const blocks = [
      { type: 'post', author: '@a' },
      { author: '@a' },
      { type: null, author: '@a' }
    ];
    const s = computeStats(blocks);
    eq(s.typeBreakdown.length, 1);
    eq(s.typeBreakdown[0].count, 1);
  });

  t('ignores entries with missing author for topAuthors', () => {
    const blocks = [
      { type: 'post' },
      { type: 'post', author: '@a' }
    ];
    const s = computeStats(blocks);
    eq(s.topAuthors.length, 1);
    eq(s.topAuthors[0].author, '@a');
  });
});
