'use strict';

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

var fromString = require('uint8arrays/from-string');
var concat = require('uint8arrays/concat');
var nanoid = require('nanoid');
var chai_js = require('aegir/utils/chai.js');
var mocha = require('../utils/mocha.js');
var delay = require('delay');
var all = require('it-all');

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

var delay__default = /*#__PURE__*/_interopDefaultLegacy(delay);
var all__default = /*#__PURE__*/_interopDefaultLegacy(all);

function testTouch(factory, options) {
  const describe = mocha.getDescribe(options);
  const it = mocha.getIt(options);
  describe('.files.touch', function () {
    this.timeout(120 * 1000);
    let ipfs;
    async function testMtime(mtime, expectedMtime) {
      const testPath = `/test-${ nanoid.nanoid() }`;
      await ipfs.files.write(testPath, fromString.fromString('Hello, world!'), { create: true });
      const stat = await ipfs.files.stat(testPath);
      chai_js.expect(stat).to.not.have.deep.property('mtime', expectedMtime);
      await ipfs.files.touch(testPath, { mtime });
      const stat2 = await ipfs.files.stat(testPath);
      chai_js.expect(stat2).to.have.deep.nested.property('mtime', expectedMtime);
    }
    before(async () => {
      ipfs = (await factory.spawn()).api;
    });
    after(() => factory.clean());
    it('should have default mtime', async function () {
      this.slow(5 * 1000);
      const testPath = `/test-${ nanoid.nanoid() }`;
      await ipfs.files.write(testPath, fromString.fromString('Hello, world!'), { create: true });
      const stat = await ipfs.files.stat(testPath);
      chai_js.expect(stat).to.not.have.property('mtime');
      await ipfs.files.touch(testPath);
      const stat2 = await ipfs.files.stat(testPath);
      chai_js.expect(stat2).to.have.property('mtime').that.does.not.deep.equal({
        secs: 0,
        nsecs: 0
      });
    });
    it('should update file mtime', async function () {
      this.slow(5 * 1000);
      const testPath = `/test-${ nanoid.nanoid() }`;
      const mtime = new Date();
      const seconds = Math.floor(mtime.getTime() / 1000);
      await ipfs.files.write(testPath, fromString.fromString('Hello, world!'), {
        create: true,
        mtime
      });
      await delay__default["default"](2000);
      await ipfs.files.touch(testPath);
      const stat = await ipfs.files.stat(testPath);
      chai_js.expect(stat).to.have.nested.property('mtime.secs').that.is.greaterThan(seconds);
    });
    it('should update directory mtime', async function () {
      this.slow(5 * 1000);
      const testPath = `/test-${ nanoid.nanoid() }`;
      const mtime = new Date();
      const seconds = Math.floor(mtime.getTime() / 1000);
      await ipfs.files.mkdir(testPath, {
        create: true,
        mtime
      });
      await delay__default["default"](2000);
      await ipfs.files.touch(testPath);
      const stat2 = await ipfs.files.stat(testPath);
      chai_js.expect(stat2).to.have.nested.property('mtime.secs').that.is.greaterThan(seconds);
    });
    it('should update the mtime for a hamt-sharded-directory', async () => {
      const path = `/foo-${ Math.random() }`;
      await ipfs.files.mkdir(path, { mtime: new Date() });
      await ipfs.files.write(`${ path }/foo.txt`, fromString.fromString('Hello world'), {
        create: true,
        shardSplitThreshold: 0
      });
      const originalMtime = (await ipfs.files.stat(path)).mtime;
      if (!originalMtime) {
        throw new Error('No originalMtime found');
      }
      await delay__default["default"](1000);
      await ipfs.files.touch(path, { flush: true });
      const updatedMtime = (await ipfs.files.stat(path)).mtime;
      if (!updatedMtime) {
        throw new Error('No updatedMtime found');
      }
      chai_js.expect(updatedMtime.secs).to.be.greaterThan(originalMtime.secs);
    });
    it('should create an empty file', async () => {
      const path = `/foo-${ Math.random() }`;
      await ipfs.files.touch(path, { flush: true });
      const bytes = concat.concat(await all__default["default"](ipfs.files.read(path)));
      chai_js.expect(bytes.slice()).to.deep.equal(Uint8Array.from([]));
    });
    it('should set mtime as Date', async function () {
      await testMtime(new Date(5000), {
        secs: 5,
        nsecs: 0
      });
    });
    it('should set mtime as { nsecs, secs }', async function () {
      const mtime = {
        secs: 5,
        nsecs: 0
      };
      await testMtime(mtime, mtime);
    });
    it('should set mtime as timespec', async function () {
      await testMtime({
        Seconds: 5,
        FractionalNanoseconds: 0
      }, {
        secs: 5,
        nsecs: 0
      });
    });
    it('should set mtime as hrtime', async function () {
      const mtime = process.hrtime();
      await testMtime(mtime, {
        secs: mtime[0],
        nsecs: mtime[1]
      });
    });
  });
}

exports.testTouch = testTouch;
