const fs = require('fs')
const util = require('util')
const readdir = util.promisify(fs.readdir)

const { test } = require('tap')
const { resolve } = require('path')

const requireInject = require('require-inject')

test('should use Arborist', (t) => {
  const ci = requireInject('../../lib/ci.js', {
    '../../lib/npm.js': {
      prefix: 'foo',
      flatOptions: {
        global: false
      }
    },
    '@npmcli/arborist': function (args) {
      t.ok(args, 'gets options object')
      this.loadVirtual = () => {
        t.ok(true, 'loadVirtual is called')
        return Promise.resolve(true)
      }
      this.reify = () => {
        t.ok(true, 'reify is called')
      }
    },
    'util': {
      'inherits': () => {},
      'promisify': (fn) => fn
    },
    'rimraf': (path) => {
      t.ok(path, 'rimraf called with path')
      return Promise.resolve(true)
    },
    '../../lib/utils/reify-output.js': function (arb) {
      t.ok(arb, 'gets arborist tree')
    }
  })
  ci(null, () => {
    t.end()
  })
})

test('should pass flatOptions to Arborist.reify', (t) => {
  const ci = requireInject('../../lib/ci.js', {
    '../../lib/npm.js': {
      prefix: 'foo',
      flatOptions: {
        production: true
      }
    },
    '@npmcli/arborist': function () {
      this.loadVirtual = () => Promise.resolve(true)
      this.reify = async (options) => {
        t.equal(options.production, true, 'should pass flatOptions to Arborist.reify')
        t.end()
      }
    }
  })
  ci(null, () => {})
})

test('should throw if package-lock.json or npm-shrinkwrap missing', (t) => {
  const testDir = t.testdir({
    'index.js': 'some contents',
    'package.json': 'some info'
  })

  const ci = requireInject('../../lib/ci.js', {
    '../../lib/npm.js': {
      prefix: testDir,
      flatOptions: {
        global: false
      }
    },
    'npmlog': {
      verbose: () => {
        t.ok(true, 'log fn called')
      }
    },
  })
  ci(null, (err, res) => {
    t.ok(err, 'throws error when there is no package-lock')
    t.notOk(res)
    t.end()
  })
})

test('should throw ECIGLOBAL', (t) => {
  const ci = requireInject('../../lib/ci.js', {
    '../../lib/npm.js': {
      prefix: 'foo',
      flatOptions: {
        global: true
      }
    }
  })
  ci(null, (err, res) => {
    t.equals(err.code, 'ECIGLOBAL', 'throws error with global packages')
    t.notOk(res)
    t.end()
  })
})

test('should remove existing node_modules before installing', (t) => {
  const testDir = t.testdir({
    'node_modules': {
      'some-file': 'some contents'
    }
  })

  const ci = requireInject('../../lib/ci.js', {
    '../../lib/npm.js': {
      prefix: testDir,
      flatOptions: {
        global: false
      }
    },
    '@npmcli/arborist': function () {
      this.loadVirtual = () => Promise.resolve(true)
      this.reify = async (options) => {
        t.equal(options.save, false, 'npm ci should never save')
        // check if node_modules was removed before reifying
        const contents = await readdir(testDir)
        const nodeModules = contents.filter((path) => path.startsWith('node_modules'))
        t.same(nodeModules, ['node_modules'], 'should only have the node_modules directory')
        t.end()
      }
    }
  })

  ci(null, () => {})
})
