const fs = require('fs')
const { resolve } = require('path')
const t = require('tap')
const requireInject = require('require-inject')

const npm = {
  globalDir: '',
  flatOptions: {
    global: false,
    prefix: '',
  },
  localPrefix: '',
}
const mocks = {
  '../../lib/npm.js': npm,
  '../../lib/utils/reify-finish.js': () => Promise.resolve(),
  '../../lib/utils/usage.js': () => 'usage instructions',
}

const uninstall = requireInject('../../lib/uninstall.js', mocks)

t.afterEach(cb => {
  npm.globalDir = ''
  npm.prefix = ''
  npm.flatOptions.global = false
  npm.flatOptions.prefix = ''
  cb()
})

t.test('remove single installed lib', t => {
  const path = t.testdir({
    'package.json': JSON.stringify({
      name: 'test-rm-single-lib',
      version: '1.0.0',
      dependencies: {
        a: '*',
        b: '*',
      },
    }),
    node_modules: {
      a: {
        'package.json': JSON.stringify({
          name: 'a',
          version: '1.0.0',
        }),
      },
      b: {
        'package.json': JSON.stringify({
          name: 'b',
          version: '1.0.0',
        }),
      },
    },
    'package-lock.json': JSON.stringify({
      name: 'test-rm-single-lib',
      version: '1.0.0',
      lockfileVersion: 2,
      requires: true,
      packages: {
        '': {
          name: 'test-rm-single-lib',
          version: '1.0.0',
          dependencies: {
            a: '*',
          },
        },
        'node_modules/a': {
          version: '1.0.0',
        },
        'node_modules/b': {
          version: '1.0.0',
        },
      },
      dependencies: {
        a: {
          version: '1.0.0',
        },
        b: {
          version: '1.0.0',
        },
      },
    }),
  })

  const b = resolve(path, 'node_modules/b')
  t.ok(() => fs.statSync(b))

  npm.flatOptions.prefix = path

  uninstall(['b'], err => {
    if (err)
      throw err

    t.throws(() => fs.statSync(b), 'should have removed package from nm')
    t.end()
  })
})

t.test('remove multiple installed libs', t => {
  const path = t.testdir({
    node_modules: {
      a: {
        'package.json': JSON.stringify({
          name: 'a',
          version: '1.0.0',
        }),
      },
      b: {
        'package.json': JSON.stringify({
          name: 'b',
          version: '1.0.0',
        }),
      },
    },
    'package-lock.json': JSON.stringify({
      name: 'test-rm-single-lib',
      version: '1.0.0',
      lockfileVersion: 2,
      requires: true,
      packages: {
        '': {
          name: 'test-rm-single-lib',
          version: '1.0.0',
          dependencies: {
            a: '*',
          },
        },
        'node_modules/a': {
          version: '1.0.0',
        },
        'node_modules/b': {
          version: '1.0.0',
        },
      },
      dependencies: {
        a: {
          version: '1.0.0',
        },
        b: {
          version: '1.0.0',
        },
      },
    }),
  })

  const a = resolve(path, 'node_modules/a')
  const b = resolve(path, 'node_modules/b')
  t.ok(() => fs.statSync(a))
  t.ok(() => fs.statSync(b))

  npm.flatOptions.prefix = path

  uninstall(['b'], err => {
    if (err)
      throw err

    t.throws(() => fs.statSync(a), 'should have removed a package from nm')
    t.throws(() => fs.statSync(b), 'should have removed b package from nm')
    t.end()
  })
})

t.test('no args local', t => {
  const path = t.testdir()

  npm.flatOptions.prefix = path

  uninstall([], err => {
    t.match(
      err,
      /Must provide a package name to remove/,
      'should throw package name required error'
    )

    t.end()
  })
})

t.test('no args global', t => {
  const path = t.testdir({
    lib: {
      node_modules: {
        a: t.fixture('symlink', '../../projects/a'),
      },
    },
    projects: {
      a: {
        'package.json': JSON.stringify({
          name: 'a',
          version: '1.0.0',
        }),
      },
    },
  })

  npm.localPrefix = resolve(path, 'projects', 'a')
  npm.globalDir = resolve(path, 'lib', 'node_modules')
  npm.flatOptions.global = true
  npm.flatOptions.prefix = path

  const a = resolve(path, 'lib/node_modules/a')
  t.ok(() => fs.statSync(a))

  uninstall([], err => {
    if (err)
      throw err

    t.throws(() => fs.statSync(a), 'should have removed global nm symlink')

    t.end()
  })
})

t.test('no args global but no package.json', t => {
  const path = t.testdir({})

  npm.prefix = path
  npm.localPrefix = path
  npm.flatOptions.global = true

  uninstall([], err => {
    t.match(
      err,
      'usage instructions',
      'should throw usage instructions'
    )

    t.end()
  })
})

t.test('unknown error reading from localPrefix package.json', t => {
  const path = t.testdir({})

  const uninstall = requireInject('../../lib/uninstall.js', {
    ...mocks,
    'read-package-json-fast': () => Promise.reject(new Error('ERR')),
  })

  npm.prefix = path
  npm.localPrefix = path
  npm.flatOptions.global = true

  uninstall([], err => {
    t.match(
      err,
      /ERR/,
      'should throw unknown error'
    )

    t.end()
  })
})
