const mockNpm = require('../fixtures/mock-npm')
const t = require('tap')

const config = {
  registry: 'https://registry.npmjs.org/',
  scope: '',
}
const flatOptions = {
  registry: 'https://registry.npmjs.org/',
  scope: '',
}
const npm = mockNpm({ config, flatOptions })

const npmlog = {}

let result = null
const npmFetch = (url, opts) => {
  result = { url, opts }
}

const mocks = {
  npmlog,
  'npm-registry-fetch': npmFetch,
}

const Logout = t.mock('../../lib/logout.js', mocks)
const logout = new Logout(npm)

t.test('token logout', async (t) => {
  t.plan(6)

  flatOptions['//registry.npmjs.org/:_authToken'] = '@foo/'

  npmlog.verbose = (title, msg) => {
    t.equal(title, 'logout', 'should have correcct log prefix')
    t.equal(
      msg,
      'clearing token for https://registry.npmjs.org/',
      'should log message with correct registry'
    )
  }

  npm.config.clearCredentialsByURI = (registry) => {
    t.equal(
      registry,
      'https://registry.npmjs.org/',
      'should clear credentials from the expected registry'
    )
  }

  npm.config.save = (type) => {
    t.equal(type, 'user', 'should save to user config')
  }

  await new Promise((res, rej) => {
    logout.exec([], (err) => {
      t.error(err, 'should not error out')

      t.same(
        result,
        {
          url: '/-/user/token/%40foo%2F',
          opts: {
            registry: 'https://registry.npmjs.org/',
            scope: '',
            '//registry.npmjs.org/:_authToken': '@foo/',
            method: 'DELETE',
            ignoreBody: true,
          },
        },
        'should call npm-registry-fetch with expected values'
      )

      delete flatOptions.token
      result = null
      mocks['npm-registry-fetch'] = null
      config.clearCredentialsByURI = null
      config.delete = null
      config.save = null
      npmlog.verbose = null

      res()
    })
  })
})

t.test('token scoped logout', async (t) => {
  t.plan(8)

  flatOptions['//diff-registry.npmjs.com/:_authToken'] = '@bar/'
  flatOptions['//registry.npmjs.org/:_authToken'] = '@foo/'
  config.scope = '@myscope'
  config['@myscope:registry'] = 'https://diff-registry.npmjs.com/'
  flatOptions.scope = '@myscope'
  flatOptions['@myscope:registry'] = 'https://diff-registry.npmjs.com/'

  npmlog.verbose = (title, msg) => {
    t.equal(title, 'logout', 'should have correcct log prefix')
    t.equal(
      msg,
      'clearing token for https://diff-registry.npmjs.com/',
      'should log message with correct registry'
    )
  }

  npm.config.clearCredentialsByURI = (registry) => {
    t.equal(
      registry,
      'https://diff-registry.npmjs.com/',
      'should clear credentials from the expected registry'
    )
  }

  npm.config.delete = (ref, type) => {
    t.equal(
      ref,
      '@myscope:registry',
      'should delete scoped registyr from config'
    )
    t.equal(type, 'user', 'should delete from user config')
  }

  npm.config.save = (type) => {
    t.equal(type, 'user', 'should save to user config')
  }

  await new Promise((res, rej) => {
    logout.exec([], (err) => {
      t.error(err, 'should not error out')

      t.same(
        result,
        {
          url: '/-/user/token/%40bar%2F',
          opts: {
            registry: 'https://registry.npmjs.org/',
            '@myscope:registry': 'https://diff-registry.npmjs.com/',
            scope: '@myscope',
            '//registry.npmjs.org/:_authToken': '@foo/', // <- removed by npm-registry-fetch
            '//diff-registry.npmjs.com/:_authToken': '@bar/',
            method: 'DELETE',
            ignoreBody: true,
          },
        },
        'should call npm-registry-fetch with expected values'
      )

      config.scope = ''
      delete flatOptions['//diff-registry.npmjs.com/:_authToken']
      delete flatOptions['//registry.npmjs.org/:_authToken']
      delete config['@myscope:registry']
      delete flatOptions.scope
      result = null
      mocks['npm-registry-fetch'] = null
      config.clearCredentialsByURI = null
      config.delete = null
      config.save = null
      npmlog.verbose = null

      res()
    })
  })
})

t.test('user/pass logout', async (t) => {
  t.plan(3)

  flatOptions['//registry.npmjs.org/:username'] = 'foo'
  flatOptions['//registry.npmjs.org/:_password'] = 'bar'

  npmlog.verbose = (title, msg) => {
    t.equal(title, 'logout', 'should have correct log prefix')
    t.equal(
      msg,
      'clearing user credentials for https://registry.npmjs.org/',
      'should log message with correct registry'
    )
  }

  npm.config.clearCredentialsByURI = () => null
  npm.config.save = () => null

  await new Promise((res, rej) => {
    logout.exec([], (err) => {
      t.error(err, 'should not error out')

      delete flatOptions['//registry.npmjs.org/:username']
      delete flatOptions['//registry.npmjs.org/:_password']
      npm.config.clearCredentialsByURI = null
      npm.config.save = null
      npmlog.verbose = null

      res()
    })
  })
})

t.test('missing credentials', (t) => {
  logout.exec([], (err) => {
    t.match(
      err.message,
      /not logged in to https:\/\/registry.npmjs.org\/, so can't log out!/,
      'should throw with expected message'
    )
    t.equal(err.code, 'ENEEDAUTH', 'should throw with expected error code')
    t.end()
  })
})

t.test('ignore invalid scoped registry config', async (t) => {
  t.plan(5)

  flatOptions['//registry.npmjs.org/:_authToken'] = '@foo/'
  config.scope = '@myscope'
  flatOptions['@myscope:registry'] = ''

  npmlog.verbose = (title, msg) => {
    t.equal(title, 'logout', 'should have correcct log prefix')
    t.equal(
      msg,
      'clearing token for https://registry.npmjs.org/',
      'should log message with correct registry'
    )
  }

  npm.config.clearCredentialsByURI = (registry) => {
    t.equal(
      registry,
      'https://registry.npmjs.org/',
      'should clear credentials from the expected registry'
    )
  }

  npm.config.delete = () => null
  npm.config.save = () => null

  await new Promise((res, rej) => {
    logout.exec([], (err) => {
      t.error(err, 'should not error out')

      t.same(
        result,
        {
          url: '/-/user/token/%40foo%2F',
          opts: {
            '//registry.npmjs.org/:_authToken': '@foo/',
            registry: 'https://registry.npmjs.org/',
            '@myscope:registry': '',
            method: 'DELETE',
            ignoreBody: true,
          },
        },
        'should call npm-registry-fetch with expected values'
      )

      delete flatOptions.token
      result = null
      mocks['npm-registry-fetch'] = null
      config.clearCredentialsByURI = null
      config.delete = null
      config.save = null
      npmlog.verbose = null

      res()
    })
  })
})
