'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var fromString = require('uint8arrays/from-string');
var chai_js = require('aegir/utils/chai.js');
var mocha = require('../utils/mocha.js');
var all = require('it-all');
var drain = require('it-drain');
var cid = require('multiformats/cid');
var base64 = require('multiformats/bases/base64');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var all__default = /*#__PURE__*/_interopDefaultLegacy(all);
var drain__default = /*#__PURE__*/_interopDefaultLegacy(drain);

async function getBaseEncodedMultihashes(ipfs) {
  const refs = await all__default["default"](ipfs.refs.local());
  return refs.map(r => base64.base64.encode(cid.CID.parse(r.ref).multihash.bytes));
}
async function shouldHaveRef(ipfs, cid) {
  return chai_js.expect(getBaseEncodedMultihashes(ipfs)).to.eventually.include(base64.base64.encode(cid.multihash.bytes));
}
async function shouldNotHaveRef(ipfs, cid) {
  return chai_js.expect(getBaseEncodedMultihashes(ipfs)).to.eventually.not.include(base64.base64.encode(cid.multihash.bytes));
}
function testGc(factory, options) {
  const describe = mocha.getDescribe(options);
  const it = mocha.getIt(options);
  describe('.repo.gc', () => {
    let ipfs;
    before(async () => {
      ipfs = (await factory.spawn()).api;
    });
    after(() => factory.clean());
    it('should run garbage collection', async () => {
      const res = await ipfs.add(fromString.fromString('apples'));
      const pinset = await all__default["default"](ipfs.pin.ls());
      chai_js.expect(pinset.map(obj => obj.cid.toString())).includes(res.cid.toString());
      await ipfs.pin.rm(res.cid);
      await all__default["default"](ipfs.repo.gc());
      const finalPinset = await all__default["default"](ipfs.pin.ls());
      chai_js.expect(finalPinset.map(obj => obj.cid.toString())).not.includes(res.cid.toString());
    });
    it('should clean up unpinned data', async () => {
      const addRes = await ipfs.add(fromString.fromString('apples'));
      const cid = addRes.cid;
      await shouldHaveRef(ipfs, cid);
      await drain__default["default"](ipfs.repo.gc());
      await shouldHaveRef(ipfs, cid);
      await ipfs.pin.rm(cid);
      await all__default["default"](ipfs.repo.gc());
      await shouldNotHaveRef(ipfs, cid);
    });
    it('should clean up removed MFS files', async () => {
      await ipfs.files.write('/test', fromString.fromString('oranges'), { create: true });
      const stats = await ipfs.files.stat('/test');
      chai_js.expect(stats.type).to.equal('file');
      await shouldHaveRef(ipfs, stats.cid);
      await drain__default["default"](ipfs.repo.gc());
      await shouldHaveRef(ipfs, stats.cid);
      await ipfs.files.rm('/test');
      await drain__default["default"](ipfs.repo.gc());
      await shouldNotHaveRef(ipfs, stats.cid);
    });
    it('should clean up block only after unpinned and removed from MFS', async () => {
      await ipfs.files.write('/test', fromString.fromString('peaches'), { create: true });
      const stats = await ipfs.files.stat('/test');
      chai_js.expect(stats.type).to.equal('file');
      const mfsFileCid = stats.cid;
      const block = await ipfs.block.get(mfsFileCid);
      const addRes = await ipfs.add(block);
      const dataCid = addRes.cid;
      await shouldHaveRef(ipfs, dataCid);
      await drain__default["default"](ipfs.repo.gc());
      await shouldHaveRef(ipfs, dataCid);
      await ipfs.files.rm('/test');
      await drain__default["default"](ipfs.repo.gc());
      await shouldNotHaveRef(ipfs, mfsFileCid);
      await shouldHaveRef(ipfs, dataCid);
      await ipfs.pin.rm(dataCid);
      await drain__default["default"](ipfs.repo.gc());
      await shouldNotHaveRef(ipfs, mfsFileCid);
      await shouldNotHaveRef(ipfs, dataCid);
    });
    it('should clean up indirectly pinned data after recursive pin removal', async () => {
      const addRes = await ipfs.add(fromString.fromString('pears'));
      const dataCid = addRes.cid;
      await ipfs.pin.rm(dataCid);
      const obj = {
        Data: fromString.fromString('fruit'),
        Links: [{
            Name: 'p',
            Hash: dataCid,
            Tsize: addRes.size
          }]
      };
      const objCid = await ipfs.object.put(obj);
      chai_js.expect((await all__default["default"](ipfs.pin.ls())).map(p => p.cid.toString())).not.includes(objCid.toString());
      await shouldHaveRef(ipfs, objCid);
      await shouldHaveRef(ipfs, dataCid);
      await ipfs.pin.add(objCid, { recursive: true });
      const pins = await all__default["default"](ipfs.pin.ls());
      chai_js.expect(pins.find(p => p.cid.toString() === dataCid.toString())).to.have.property('type', 'indirect');
      await drain__default["default"](ipfs.repo.gc());
      await shouldHaveRef(ipfs, objCid);
      await shouldHaveRef(ipfs, dataCid);
      await ipfs.pin.rm(objCid.toString());
      await drain__default["default"](ipfs.repo.gc());
      await shouldNotHaveRef(ipfs, objCid);
      await shouldNotHaveRef(ipfs, dataCid);
    });
  });
}

exports.testGc = testGc;
