#!/usr/bin/env node

const heimdall = require('@hyperdivision/heimdall')
const { Responder } = require('@hyperdivision/heimdall-pairing')
const hyperswarm = require('hyperswarm')
const fs = require('fs')
const minimist = require('minimist')
const pump = require('pump')
const path = require('path')

const argv = minimist(process.argv, {
  alias: {
    directory: 'd',
    bootstrap: 'b',
    operation: 'o',
    help: 'h'
  },
  default: {
    directory: 'heimdall'
  }
})

if (argv.help) {
  console.log(`Usage: heimdall-server [options]
  -d, --directory (defaults to ./heimdall)
  -b, --bootstrap (set bootstrap phrase)
  -o, --operation (add an operation)
  -h, --help      (print this help)`)
  process.exit(0)
}

bootstrap()

function normalise (dk) {
  const words = dk.trim().split(' ').map(s => s.trim())
  if (words.length !== 3) return null
  return words.join(' ')
}

function bootstrap () {
  if (fs.existsSync(argv.d)) {
    console.log('heimdall appears boostrapped, skipping ...')
    return start()
  }

  if (!argv.bootstrap) {
    console.error('Pass the bootstrap discovery phrase, --bootstrap="word1 word2 word3"')
    process.exit(1)
  }

  const dk = normalise(argv.bootstrap)
  if (!dk || !Responder.validateDiscoveryKey(dk)) {
    console.error('Invalid bootstrap key')
    process.exit(2)
  }

  const r = new Responder({
    propose (key, profile, profileSignature, done) {
      console.log('Received bootstrap profile for key ' + key.toString('hex') + ':')
      console.log(profile)

      const server = start([{ key, profile, profileSignature }])

      server.ready(function (err) {
        setTimeout(() => done(err, server.key), 250)
      })
    }
  })

  console.log('Using discover key: ' + dk)
  r.setDiscoveryKey(dk)
  r.once('bind', function () {
    r.network.discovery.holepunchable(function (err, yes) {
      if (err) return console.error('Network discovery error:', err)
      if (yes) console.log('Network is holepunchable')
      else console.log('Network is not holepunchable')
    })
  })

  r.on('pin', function () {
    console.log('Pin: ' + r.pin)
  })
}

function start (genesisUsers) {
  const server = heimdall.server(argv.d, {
    genesisUsers,
    allowWildcard: true
  })

  if (argv.operation) {
    for (const dir of [].concat(argv.operation || [])) {
      const create = req(dir)
      const op = create(heimdall)
      server.operation(op.operation, op)
    }
  }

  server.operation(heimdall.server.OPERATION_WILDCARD, {
    execute (prop, state, done) {
      done()
    }
  })

  const swarm = hyperswarm()

  swarm.on('connection', function (connection) {
    console.log('Replication started')
    pump(connection, server.replicate({ live: true }), connection, function (err) {
      console.log('Replication ended', err)
    })
  })

  server.ready(function () {
    swarm.join(server.discoveryKey, {
      announce: true
    })
  })

  return server
}

function req (name) {
  try {
    return require(name)
  } catch (_) {
    return require(path.resolve(name))
  }
}
