var fs = require('graceful-fs')
var path = require('path')

var mkdirp = require('mkdirp')
var osenv = require('osenv')
var rimraf = require('rimraf')
var test = require('tap').test

var common = require('../common-tap.js')

var pkg = path.resolve(__dirname, 'optional-metadep-rollback-collision')
var deps = path.resolve(pkg, 'deps')
var opdep = path.resolve(pkg, 'node_modules', 'opdep')
var cache = path.resolve(pkg, 'cache')
var pidfile = path.resolve(pkg, 'child.pid')

var json = {
  name: 'optional-metadep-rollback-collision',
  version: '1.0.0',
  description: 'let\'s just see about that race condition',
  optionalDependencies: {
    opdep: 'file:./deps/opdep'
  }
}

var d1 = {
  name: 'd1',
  version: '1.0.0',
  description: 'I FAIL CONSTANTLY',
  scripts: {
    preinstall: 'sleep 1'
  },
  dependencies: {
    foo: 'http://localhost:8080/'
  }
}

var d2 = {
  name: 'd2',
  version: '1.0.0',
  description: 'how do you *really* know you exist?',
  scripts: {
    postinstall: 'node blart.js'
  },
  dependencies: {
    'graceful-fs': '^3.0.2',
    mkdirp: '^0.5.0',
    rimraf: '^2.2.8'
  }
}

var opdep_json = {
  name: 'opdep',
  version: '1.0.0',
  description: 'To explode, of course!',
  main: 'index.js',
  scripts: {
    preinstall: 'node bad-server.js'
  },
  dependencies: {
    d1: 'file:../d1',
    d2: 'file:../d2'
  }
}

var badServer = function () { /*
var createServer = require('http').createServer
var spawn = require('child_process').spawn
var fs = require('fs')
var path = require('path')
var pidfile = path.resolve(__dirname, '..', '..', 'child.pid')

if (process.argv[2]) {
  console.log('ok')
  createServer(function (req, res) {
    setTimeout(function () {
      res.writeHead(404)
      res.end()
    }, 1000)
    this.close()
  }).listen(8080)
} else {
  var child = spawn(
    process.execPath,
    [__filename, 'whatever'],
    {
      stdio: [0, 1, 2],
      detached: true
    }
  )
  child.unref()

  // kill any prior children, if existing.
  try {
    var pid = +fs.readFileSync(pidfile)
    process.kill(pid, 'SIGKILL')
  } catch (er) {}

  fs.writeFileSync(pidfile, child.pid + '\n')
}
*/ }.toString().split('\n').slice(1, -1).join('\n')

var blart = function () { /*
var rando = require('crypto').randomBytes
var resolve = require('path').resolve

var mkdirp = require('mkdirp')
var rimraf = require('rimraf')
var writeFile = require('graceful-fs').writeFile

var BASEDIR = resolve(__dirname, 'arena')

var keepItGoingLouder = {}
var writers = 0
var errors = 0

function gensym () { return rando(16).toString('hex') }

function writeAlmostForever (filename) {
  if (!keepItGoingLouder[filename]) {
    writers--
    if (writers < 1) return done()
  } else {
    writeFile(filename, keepItGoingLouder[filename], function (err) {
      if (err) errors++

      writeAlmostForever(filename)
    })
  }
}

function done () {
  rimraf(BASEDIR, function () {
    if (errors > 0) console.log('not ok - %d errors', errors)
    else console.log('ok')
  })
}

mkdirp(BASEDIR, function go () {
  for (var i = 0; i < 16; i++) {
    var filename = resolve(BASEDIR, gensym() + '.txt')

    keepItGoingLouder[filename] = ''
    for (var j = 0; j < 512; j++) keepItGoingLouder[filename] += filename

    writers++
    writeAlmostForever(filename)
  }

  setTimeout(function viktor () {
    // kill all the writers
    keepItGoingLouder = {}
  }, 3 * 1000)
})
*/ }.toString().split('\n').slice(1, -1).join('\n')
test('setup', function (t) {
  cleanup()

  mkdirp.sync(pkg)
  fs.writeFileSync(
    path.join(pkg, 'package.json'),
    JSON.stringify(json, null, 2)
  )

  mkdirp.sync(path.join(deps, 'd1'))
  fs.writeFileSync(
    path.join(deps, 'd1', 'package.json'),
    JSON.stringify(d1, null, 2)
  )

  mkdirp.sync(path.join(deps, 'd2'))
  fs.writeFileSync(
    path.join(deps, 'd2', 'package.json'),
    JSON.stringify(d2, null, 2)
  )
  fs.writeFileSync(path.join(deps, 'd2', 'blart.js'), blart)

  mkdirp.sync(path.join(deps, 'opdep'))
  fs.writeFileSync(
    path.join(deps, 'opdep', 'package.json'),
    JSON.stringify(opdep_json, null, 2)
  )
  fs.writeFileSync(path.join(deps, 'opdep', 'bad-server.js'), badServer)

  t.end()
})

test('go go test racer', function (t) {
  common.npm(
    [
      '--prefix', pkg,
      '--fetch-retries', '0',
      '--loglevel', 'silent',
      '--cache', cache,
      'install'
    ],
    {
      cwd: pkg,
      env: {
        PATH: process.env.PATH,
        Path: process.env.Path
      },
      stdio: [0, 'pipe', 2]
    },
    function (er, code, stdout, stderr) {
      t.ifError(er, 'install ran to completion without error')
      t.is(code, 0, 'npm install exited with code 0')
      t.is(stderr, '')

      // stdout should be empty, because we only have one, optional, dep and
      // if it fails we shouldn't try installing anything
      t.equal(stdout, '')
      t.notOk(/not ok/.test(stdout), 'should not contain the string \'not ok\'')
      t.end()
    }
  )
})

test('verify results', function (t) {
  t.throws(function () {
    fs.statSync(opdep)
  })
  t.end()
})

test('cleanup', function (t) {
  cleanup()
  t.end()
})

function cleanup () {
  process.chdir(osenv.tmpdir())
  try {
    var pid = +fs.readFileSync(pidfile)
    process.kill(pid, 'SIGKILL')
  } catch (er) {}

  rimraf.sync(pkg)
}
