import { jid_to_id } from './utils';
import Presence from './presence';
import Stream from './bacon_stream';
import * as _ from 'lodash';
import * as Bacon from 'baconjs';


export default function(connection, thisJid, logger) {
	return {
		copy: function(args) {
			_.forEach(args, (v, k) => {
				this[k] = v;
			});
			this.kill();
			this._create();

		},
		_create: function(){
			var onRosterChanged = rosterChanged => function (iq) {
		        var self = this;
		        $(iq).find('item').each(function () {
		            var sub = $(this).attr('subscription');
		            var jid = $(this).attr('jid');
		            var name = $(this).attr('name') || jid;
		            var jid_id = jid_to_id(jid);

					if(rosterChanged) {
						rosterChanged(sub, jid, name);
					}
		        });

		        return true;
		    };
			this._rosterHandle = connection.addHandler(onRosterChanged(this.rosterHandler), "jabber:iq:roster", "iq", "set");
		},
		_notifyContact: function(sub, jid, name){
			return { 
				action: "added",
				jid: jid,
				name: name
			};
		},
		_notifySubscription: function(jid, username, resource, status){
			return {
				jid:jid, 
				name: username, 
				resource: resource, 
				status: status
			};
		},
		create: function(){
			this._create();
			this.presence = new Presence(connection, (presence, jid) => presence.approve(jid),  this._notifySubscription, logger);
			return this;
		},
		connect: function(){
    		return this._createConnectionPromise().then(roster => roster.presence.connect()).then(presence => connection.send($pres()));
    	} ,
    	createPresenceStream: function() {
			return new Stream(this.presence, 'presenceChangedHandler', this._notifySubscription);
    	},
    	createContactStream: function() {
    		return new Stream(this, 'rosterHandler', this._notifyContact, r => r._getContacts());
    	},
    	_getContacts: function(resolve, reject) {
    		var roster = this;
    		var onRoster = rosterChanged => iq => {
				$(iq).find('item').each(function () {
			            var jid = $(this).attr('jid');
			            var name = $(this).attr('name') || jid;
			            if(rosterChanged) {
			            	rosterChanged('add', jid, name);
			            }
			        });
			        if(resolve) resolve(roster);
				};
			var iq = $iq({type: 'get'}).c('query', {xmlns: 'jabber:iq:roster'});
			connection.sendIQ(iq, onRoster(this.rosterHandler));
    	},
		_createConnectionPromise: function() {
			var roster = this;
			return new Promise((resolve, reject) => {
				this._getContacts(resolve, reject);
			});
		},

		_createContact: function(jid, pname) {
	    	return {
	    		jid: jid,
		    	name: pname,
	        	resources: {},
	        	isOnline: function(){
	        		return _.any(this.resources, status => status == "online");
	        	},
	        	isAway: function(){
	        		return !this.isOnline && _.any(this.resources, status => status == "away");
	        	},
	        	isOffline: function(){
	        		return _.every(this.resources, status => status == "offline");
	        	},
	        	getStatus: function(){
	        		var status = "offline";
	        		_.forEach(this.resources, s => {
	        			if(s == "online") status = "online";
	        			else if(s == "offline" && s == "away") status = "away";
	        		});
	        		return status;
	        	}
        	};
	    },
		

    	subscribe: function(jid, message, nick) {
	    	var pres = $pres({to: jid, from: thisJid, type: "subscribe"});
	        if (message && message !== "") {
	            pres.c("status").t(message).up();
	        }
	        if (nick && nick !== "") {
	            pres.c('nick', {'xmlns': Strophe.NS.NICK}).t(nick).up();
	        }
	        connection.send(pres);
	    },
    	kill: function() {
    		this.presence.kill();
    		connection.deleteHandler(this._rosterHandle);
    	}
    }.create();

}