const t = require('tap')
const { load: _loadMockNpm } = require('../../fixtures/mock-npm.js')
const { sep } = require('path')

const fixture = {
  'package.json': JSON.stringify({
    name: 'thispkg',
    version: '1.2.3',
    repository: 'https://example.com/thispkg.git',
  }),
  norepo: {
    'package.json': JSON.stringify({
      name: 'norepo',
      version: '1.2.3',
    }),
  },
  'repoobbj-nourl': {
    'package.json': JSON.stringify({
      name: 'repoobj-nourl',
      repository: { no: 'url' },
    }),
  },
  hostedgit: {
    'package.json': JSON.stringify({
      repository: 'git://github.com/foo/hostedgit',
    }),
  },
  hostedgitat: {
    'package.json': JSON.stringify({
      repository: 'git@github.com:foo/hostedgitat',
    }),
  },
  hostedssh: {
    'package.json': JSON.stringify({
      repository: 'ssh://git@github.com/foo/hostedssh',
    }),
  },
  hostedgitssh: {
    'package.json': JSON.stringify({
      repository: 'git+ssh://git@github.com/foo/hostedgitssh',
    }),
  },
  hostedgithttp: {
    'package.json': JSON.stringify({
      repository: 'git+http://github.com/foo/hostedgithttp',
    }),
  },
  hostedgithttps: {
    'package.json': JSON.stringify({
      repository: 'git+https://github.com/foo/hostedgithttps',
    }),
  },
  hostedgitobj: {
    'package.json': JSON.stringify({
      repository: { url: 'git://github.com/foo/hostedgitobj' },
    }),
  },
  hostedgitatobj: {
    'package.json': JSON.stringify({
      repository: { url: 'git@github.com:foo/hostedgitatobj' },
    }),
  },
  hostedsshobj: {
    'package.json': JSON.stringify({
      repository: { url: 'ssh://git@github.com/foo/hostedsshobj' },
    }),
  },
  hostedgitsshobj: {
    'package.json': JSON.stringify({
      repository: { url: 'git+ssh://git@github.com/foo/hostedgitsshobj' },
    }),
  },
  hostedgithttpobj: {
    'package.json': JSON.stringify({
      repository: { url: 'git+http://github.com/foo/hostedgithttpobj' },
    }),
  },
  hostedgithttpsobj: {
    'package.json': JSON.stringify({
      repository: { url: 'git+https://github.com/foo/hostedgithttpsobj' },
    }),
  },
  unhostedgit: {
    'package.json': JSON.stringify({
      repository: 'git://gothib.com/foo/unhostedgit',
    }),
  },
  unhostedgitat: {
    'package.json': JSON.stringify({
      repository: 'git@gothib.com:foo/unhostedgitat',
    }),
  },
  unhostedssh: {
    'package.json': JSON.stringify({
      repository: 'ssh://git@gothib.com/foo/unhostedssh',
    }),
  },
  unhostedgitssh: {
    'package.json': JSON.stringify({
      repository: 'git+ssh://git@gothib.com/foo/unhostedgitssh',
    }),
  },
  unhostedgithttp: {
    'package.json': JSON.stringify({
      repository: 'git+http://gothib.com/foo/unhostedgithttp',
    }),
  },
  unhostedgithttps: {
    'package.json': JSON.stringify({
      repository: 'git+https://gothib.com/foo/unhostedgithttps',
    }),
  },
  unhostedgitobj: {
    'package.json': JSON.stringify({
      repository: { url: 'git://gothib.com/foo/unhostedgitobj' },
    }),
  },
  unhostedgitatobj: {
    'package.json': JSON.stringify({
      repository: { url: 'git@gothib.com:foo/unhostedgitatobj' },
    }),
  },
  unhostedsshobj: {
    'package.json': JSON.stringify({
      repository: { url: 'ssh://git@gothib.com/foo/unhostedsshobj' },
    }),
  },
  unhostedgitsshobj: {
    'package.json': JSON.stringify({
      repository: { url: 'git+ssh://git@gothib.com/foo/unhostedgitsshobj' },
    }),
  },
  unhostedgithttpobj: {
    'package.json': JSON.stringify({
      repository: { url: 'git+http://gothib.com/foo/unhostedgithttpobj' },
    }),
  },
  unhostedgithttpsobj: {
    'package.json': JSON.stringify({
      repository: { url: 'git+https://gothib.com/foo/unhostedgithttpsobj' },
    }),
  },
  directory: {
    'package.json': JSON.stringify({
      repository: {
        type: 'git',
        url: 'git+https://github.com/foo/test-repo-with-directory.git',
        directory: 'some/directory',
      },
    }),
  },
}

const workspaceFixture = {
  'package.json': JSON.stringify({
    name: 'workspaces-test',
    version: '1.2.3-test',
    workspaces: ['workspace-a', 'workspace-b', 'workspace-c'],
    repository: 'https://github.com/npm/workspaces-test',
  }),
  'workspace-a': {
    'package.json': JSON.stringify({
      name: 'workspace-a',
      version: '1.2.3-a',
      repository: 'http://repo.workspace-a/',
    }),
  },
  'workspace-b': {
    'package.json': JSON.stringify({
      name: 'workspace-b',
      version: '1.2.3-n',
      repository: 'https://github.com/npm/workspace-b',
    }),
  },
  'workspace-c': JSON.stringify({
    'package.json': {
      name: 'workspace-n',
      version: '1.2.3-n',
    },
  }),
}

// keep a tally of which urls got opened
let opened = {}
const openUrl = async (npm, url, errMsg) => {
  opened[url] = opened[url] || 0
  opened[url]++
}
t.afterEach(() => opened = {})

const loadMockNpm = async (t, prefixDir) => {
  const res = await _loadMockNpm(t, {
    mocks: { '../../lib/utils/open-url.js': openUrl },
    prefixDir,
  })
  return res
}

t.test('open repo urls', async t => {
  const { npm } = await loadMockNpm(t, fixture)
  const expect = {
    hostedgit: 'https://github.com/foo/hostedgit',
    hostedgitat: 'https://github.com/foo/hostedgitat',
    hostedssh: 'https://github.com/foo/hostedssh',
    hostedgitssh: 'https://github.com/foo/hostedgitssh',
    hostedgithttp: 'https://github.com/foo/hostedgithttp',
    hostedgithttps: 'https://github.com/foo/hostedgithttps',
    hostedgitobj: 'https://github.com/foo/hostedgitobj',
    hostedgitatobj: 'https://github.com/foo/hostedgitatobj',
    hostedsshobj: 'https://github.com/foo/hostedsshobj',
    hostedgitsshobj: 'https://github.com/foo/hostedgitsshobj',
    hostedgithttpobj: 'https://github.com/foo/hostedgithttpobj',
    hostedgithttpsobj: 'https://github.com/foo/hostedgithttpsobj',
    unhostedgit: 'https://gothib.com/foo/unhostedgit',
    unhostedssh: 'https://gothib.com/foo/unhostedssh',
    unhostedgitssh: 'https://gothib.com/foo/unhostedgitssh',
    unhostedgithttp: 'http://gothib.com/foo/unhostedgithttp',
    unhostedgithttps: 'https://gothib.com/foo/unhostedgithttps',
    unhostedgitobj: 'https://gothib.com/foo/unhostedgitobj',
    unhostedsshobj: 'https://gothib.com/foo/unhostedsshobj',
    unhostedgitsshobj: 'https://gothib.com/foo/unhostedgitsshobj',
    unhostedgithttpobj: 'http://gothib.com/foo/unhostedgithttpobj',
    unhostedgithttpsobj: 'https://gothib.com/foo/unhostedgithttpsobj',
    directory: 'https://github.com/foo/test-repo-with-directory/tree/HEAD/some/directory',
    '.': 'https://example.com/thispkg',
  }
  const keys = Object.keys(expect)
  t.plan(keys.length)
  keys.forEach(pkg => {
    t.test(pkg, async t => {
      await npm.exec('repo', [['.', pkg].join(sep)])
      const url = expect[pkg]
      t.match({
        [url]: 1,
      }, opened, `opened ${url}`, { opened })
      t.end()
    })
  })
})

t.test('fail if cannot figure out repo url', async t => {
  const { npm } = await loadMockNpm(t, fixture)

  const cases = [
    'norepo',
    'repoobbj-nourl',
    'unhostedgitat',
    'unhostedgitatobj',
  ]

  t.plan(cases.length)

  cases.forEach(pkg => {
    t.test(pkg, async t => {
      t.rejects(
        npm.exec('repo', [['.', pkg].join(sep)]),
        { pkgid: pkg }
      )
    })
  })
})

t.test('open default package if none specified', async t => {
  const { npm } = await loadMockNpm(t, fixture)
  await npm.exec('repo', [])
  t.equal(opened['https://example.com/thispkg'], 1, 'opened expected url', { opened })
})

t.test('workspaces', async t => {
  const { npm } = await loadMockNpm(t, workspaceFixture)

  t.afterEach(() => {
    npm.config.set('workspaces', null)
    npm.config.set('workspace', [])
    npm.config.set('include-workspace-root', false)
  })

  t.test('include workspace root', async (t) => {
    npm.config.set('workspaces', true)
    npm.config.set('include-workspace-root', true)
    await npm.exec('repo', [])
    t.match({
      'https://github.com/npm/workspaces-test': 1,
      'https://repo.workspace-a/': 1, // Gets translated to https!
      'https://github.com/npm/workspace-b': 1,
    }, opened, 'opened two valid repo urls')
  })

  t.test('all workspaces', async (t) => {
    npm.config.set('workspaces', true)
    await npm.exec('repo', [])
    t.match({
      'https://repo.workspace-a/': 1, // Gets translated to https!
      'https://github.com/npm/workspace-b': 1,
    }, opened, 'opened two valid repo urls')
  })

  t.test('one workspace', async (t) => {
    npm.config.set('workspace', ['workspace-a'])
    await npm.exec('repo', [])
    t.match({
      'https://repo.workspace-a/': 1,
    }, opened, 'opened one requested repo urls')
  })

  t.test('invalid workspace', async (t) => {
    npm.config.set('workspace', ['workspace-x'])
    await t.rejects(
      npm.exec('repo', []),
      /workspace-x/
    )
    t.match({}, opened, 'opened no repo urls')
  })

  t.test('package arg and workspace', async (t) => {
    npm.config.set('workspace', ['workspace-a'])
    await npm.exec('repo', ['.'])
    t.match({
      'https://github.com/npm/workspaces-test': 1,
    }, opened, 'opened url for package arg, not workspace')
  })
})
