var Netflux = require("netflux-websocket");
var WebSocket = require("ws"); // jshint ignore:line
var nThen = require("nthen");

var Util = require("../../www/common/common-util");

var Nacl = require("tweetnacl/nacl-fast");

var Client = module.exports;

var createNetwork = Client.createNetwork = function (url, cb) {
    var CB = Util.once(cb);

    var info = {};

    Netflux.connect(url, function (url) {
        // this websocket seems to never close properly if the error is
        // ECONNREFUSED
        info.websocket = new WebSocket(url)
        .on('error', function (err) {
            CB(err);
        })
        .on('close', function (/* err */) {
            delete info.websocket;
        });
        return info.websocket;
    }).then(function (network) {
        info.network = network;
        CB(void 0, info);
    }, function (err) {
        CB(err);
    });
};

var die = function (client) {
    var disconnect = Util.find(client, ['config', 'network', 'disconnect']);
    if (typeof(disconnect) === 'function') {
        disconnect();
    } else {
        console.error("disconnect was not a function");
    }
    var close = Util.find(client, ['config', 'websocket', 'close']);
    if (typeof(close) === 'function') {
        client.config.websocket.close();
    } else {
        console.error("close was not a function");
    }
};

Client.create = function (config, cb) {
    if (typeof(config) === 'function') {
        cb = config;
        config = {};
    }
    var client = {
        config: config,
    };
    var CB = Util.once(function (err, arg) {
        if (err) { die(client); }
        cb(err, arg);
    });

    client.shutdown = function () {
        die(client);
    };

    nThen(function (w) {
        if (config.network) { return; }
        // connect to the network...
        createNetwork('ws://localhost:3000/cryptpad_websocket', w(function (err, info) {
            if (err) {
                w.abort();
                return void CB(err);
            }
            config.network = info.network;
            config.websocket = info.websocket;
        }));
    }).nThen(function (w) {
        // make sure the network has a historyKeeper id on it
        // we're responsible for adding it
        if (config.network.historyKeeper) { return; }
        var channel = Util.uint8ArrayToHex(Nacl.randomBytes(16));
        config.network.join(channel).then(w(function (wc) {
            wc.members.some(function (member) {
                if (member.length !== 16) { return; }
                config.network.historyKeeper = member;
                return true;
            });
            wc.leave();
        }), function (err) {
            w.abort();
            CB(err);
        });
    }).nThen(function () {
        CB(void 0, client);
    });
};