'use strict';

var peerId = require('peer-id');
var PeerInfo = require('peer-info');
var multiaddr = require('multiaddr');
var Libp2pNode = require('libp2p-ipfs').Node;

module.exports = function libp2p(self) {
  var OFFLINE_ERROR = new Error('This command must be run in online mode. Try running \'ipfs daemon\' first.');

  return {
    start: function start(callback) {
      self._libp2pNode = new Libp2pNode(self._peerInfo);
      self._libp2pNode.start(function () {
        // TODO connect to bootstrap nodes, it will get us more addrs
        self._peerInfo.multiaddrs.forEach(function (ma) {
          console.log('Swarm listening on', ma.toString());
        });
        callback();
      });
    },
    stop: function stop(callback) {
      try {
        self._libp2pNode.swarm.close(callback);
      } catch (err) {
        console.log('It is fine :)');
      }
    },
    swarm: {
      peers: function peers(callback) {
        if (!self._libp2pNode) {
          return callback(OFFLINE_ERROR);
        }

        callback(null, self._peerInfoBook.getAll());
      },
      // all the addrs we know
      addrs: function addrs(callback) {
        if (!self._libp2pNode) {
          return callback(OFFLINE_ERROR);
        }
        // TODO
        throw new Error('Not implemented');
      },
      localAddrs: function localAddrs(callback) {
        if (!self._libp2pNode) {
          return callback(OFFLINE_ERROR);
        }

        callback(null, self._peerInfo.multiaddrs);
      },
      connect: function connect(ma, callback) {
        if (!self._libp2pNode) {
          return callback(OFFLINE_ERROR);
        }

        var idStr = ma.toString().match(/\/ipfs\/(.*)/);
        if (!idStr) {
          return callback(new Error('invalid multiaddr'));
        }
        var id = peerId.createFromB58String(idStr[1]);
        var peer = new PeerInfo(id);

        ma = ma.toString().replace(/\/ipfs\/(.*)/, ''); // FIXME remove this when multiaddr supports ipfs

        peer.multiaddr.add(multiaddr(ma));
        self._peerInfoBook.put(peer);

        self._libp2pNode.swarm.dial(peer, function (err) {
          callback(err, id);
        });
      },
      disconnect: function disconnect(callback) {
        if (!self._libp2pNode) {
          return callback(OFFLINE_ERROR);
        }

        throw new Error('Not implemented');
      },
      filters: function filters() {
        // TODO
        throw new Error('Not implemented');
      }
    },
    routing: {},
    records: {},
    ping: function ping() {
      throw new Error('Not implemented');
    }
  };
};