define([
	'config/roles',
	'world/atlas',
	'items/generator',
	'misc/random',
	'items/config/slots',
	'security/io',
	'config/factions',
	'security/connections'
], function (
	roles,
	atlas,
	generator,
	random,
	configSlots,
	io,
	factions,
	connections
) {
	var commandRoles = {
		//Regular players
		join: 0,
		leave: 0,
		unEq: 0,

		//Mods
		mute: 5,
		unmute: 5,

		//Admin
		getItem: 10,
		getGold: 10,
		setLevel: 10,
		godMode: 10,
		clearInventory: 10,
		completeQuests: 10,
		getReputation: 10,
		loseReputation: 10,
		setStat: 10,
		die: 10,
		getXp: 10
	};

	var localCommands = [
		'join',
		'leave',
		'mute',
		'unmute'
	];

	return {
		customChannels: [],
		roleLevel: null,

		init: function (blueprint) {
			if (this.customChannels) {
				this.customChannels = this.customChannels
					.filter((c, i) => (this.customChannels.indexOf(c) == i));
			}

			this.roleLevel = roles.getRoleLevel(this.obj);
		},

		onBeforeChat: function (msg) {
			var messageText = msg.message;
			if (messageText[0] != '/')
				return;

			messageText = messageText.substr(1).split(' ');
			var actionName = messageText.splice(0, 1)[0].toLowerCase();
			actionName = Object.keys(commandRoles).find(a => (a.toLowerCase() == actionName));

			if (!actionName)
				return;
			else if (this.roleLevel < commandRoles[actionName])
				return;

			msg.ignore = true;

			var config = {};
			if ((messageText.length == 1) && (messageText[0].indexOf('=') == -1))
				config = messageText[0];
			else {
				messageText.forEach(function (m) {
					m = m.split('=');
					config[m[0]] = m[1];
				});
			}

			if (localCommands.indexOf(actionName) > -1) {
				this[actionName].call(this, config);
			} else {
				atlas.performAction(this.obj, {
					cpn: 'social',
					method: actionName,
					data: config
				});
			}
		},

		//actions
		join: function (value) {
			if (typeof (value) != 'string')
				return;

			value = value.split(' ').join('');
			if (value.lengh == 0)
				return;

			var obj = this.obj;

			var channels = obj.auth.customChannels;
			if (!channels.some(c => (c == value)))
				channels.push(value);
			else
				return;

			channels.push(value);

			var charname = obj.auth.charname;
			io.set({
				ent: charname,
				field: 'customChannels',
				value: JSON.stringify(channels)
			});

			obj.socket.emit('events', {
				onGetMessages: [{
					messages: [{
						class: 'color-yellowB',
						message: 'joined channel: ' + value,
						type: 'info'
					}]
				}]
			});

			obj.socket.emit('event', {
				event: 'onJoinChannel',
				data: value
			});
		},

		leave: function (value) {
			if (typeof (value) != 'string')
				return;

			var obj = this.obj;

			var channels = obj.auth.customChannels;
			if (!channels.some(c => (c == value))) {
				obj.socket.emit('events', {
					onGetMessages: [{
						messages: [{
							class: 'color-redA',
							message: 'you are not currently in that channel',
							type: 'info'
						}]
					}]
				});

				return;
			}

			var channels = obj.auth.customChannels;
			channels.spliceWhere(c => (c == value));

			var charname = obj.auth.charname;
			io.set({
				ent: charname,
				field: 'customChannels',
				value: JSON.stringify(channels)
			});

			obj.socket.emit('event', {
				event: 'onLeaveChannel',
				data: value
			});

			this.obj.socket.emit('events', {
				onGetMessages: [{
					messages: [{
						class: 'color-yellowB',
						message: 'left channel: ' + value,
						type: 'info'
					}]
				}]
			});
		},

		isInChannel: function (character, channel) {
			return character.auth.customChannels.some(c => (c == channel));
		},

		unEq: function () {
			var eq = this.obj.equipment;
			Object.keys(eq.eq).forEach(function (slot) {
				eq.unequip(eq.eq[slot]);
			});
		},

		mute: function (target, reason) {
			if (typeof (target) == 'object') {
				var keys = Object.keys(target);
				target = keys[0];
				reason = keys[1];
			}

			if (target == this.obj.name)
				return;

			var o = connections.players.find(o => (o.name == target));
			if (!o)
				return;

			var role = roles.getRoleLevel(o);
			if (role >= this.roleLevel)
				return;

			var social = o.social;
			if (social.muted) {
				this.sendMessage('That player has already been muted', 'color-redA');
				return;
			}

			var reasonMsg = '';
			if (reason)
				reasonMsg = ' (' + reason + ')';

			social.muted = true;
			this.sendMessage('Successfully muted ' + target, 'color-yellowB');
			this.sendMessage('You have been muted' + reasonMsg, 'color-yellowB', o);

			atlas.updateObject(o, {
				components: [{
					type: 'social',
					muted: true
				}]
			});

			io.set({
				ent: new Date(),
				field: 'modLog',
				value: JSON.stringify({
					source: this.obj.name,
					command: 'mute',
					target: target,
					reason: reason
				})
			});
		},

		unmute: function (target, reason) {
			if (typeof (target) == 'object') {
				var keys = Object.keys(target);
				target = keys[0];
				reason = keys[1];
			}

			if (target == this.obj.name)
				return;

			var o = connections.players.find(o => (o.name == target));
			if (!o)
				return;

			var role = roles.getRoleLevel(o);
			if (role >= this.roleLevel)
				return;

			var social = o.social;
			if (!social.muted) {
				this.sendMessage('That player is not muted', 'color-redA');
				return;
			}

			var reasonMsg = '';
			if (reason)
				reasonMsg = ' (' + reason + ')';

			delete social.muted;
			this.sendMessage('Successfully unmuted ' + target, 'color-yellowB');
			this.sendMessage('You have been unmuted' + reasonMsg, 'color-yellowB', o);

			atlas.updateObject(o, {
				components: [{
					type: 'social',
					muted: null
				}]
			});

			io.set({
				ent: new Date(),
				field: 'modLog',
				value: JSON.stringify({
					source: this.obj.name,
					command: 'unmute',
					target: target,
					reason: reason
				})
			})
		},

		clearInventory: function () {
			var inventory = this.obj.inventory;

			inventory.items
				.filter(i => !i.eq)
				.map(i => i.id)
				.forEach(i => inventory.destroyItem(i, null, true));
		},

		getItem: function (config) {
			if (config.slot == 'set') {
				configSlots.slots.forEach(function (s) {
					if (s == 'tool')
						return;

					var newConfig = extend(true, {}, config, {
						slot: s
					});

					this.getItem(newConfig);
				}, this);

				return;
			}

			if (config.stats)
				config.stats = config.stats.split(',');

			if (config.name)
				config.name = config.name.split('_').join(' ');

			if (config.spellName)
				config.spellName = config.spellName.split('_').join(' ');

			if (config.type)
				config.type = config.type.split('_').join(' ');

			if (config.sprite)
				config.sprite = config.sprite.split('_');

			var spritesheet = config.spritesheet;
			delete config.spritesheet;

			var factions = (config.factions || '').split(',');
			delete config.factions;

			var safe = config.safe;
			delete config.safe;

			var eq = config.eq;
			delete config.eq;

			var item = generator.generate(config);

			if (safe) {
				item.noDrop = true;
				item.noDestroy = true;
				item.noSalvage = true;
			}

			factions.forEach(function (f) {
				if (f == '')
					return;

				var faction = factions.getFaction(f);
				faction.uniqueStat.generate(item);

				item.factions = [];
				item.factions.push({
					id: f,
					tier: 3
				});
			});

			if (spritesheet)
				item.spritesheet = spritesheet;

			var newItem = this.obj.inventory.getItem(item);

			if (eq)
				this.obj.equipment.equip(newItem.id);
		},

		getGold: function (amount) {
			var newGold = this.obj.trade.gold + ~~amount;
			newGold = Math.max(-1000000000, Math.min(1000000000, newGold));

			this.obj.trade.gold = newGold;
			this.obj.syncer.set(true, 'trade', 'gold', newGold);
		},

		setLevel: function (level) {
			var obj = this.obj;
			var syncer = obj.syncer;

			level = Math.max(1, ~~level);

			var stats = obj.stats;
			var values = stats.values;
			var oldLevel = values.level;

			values.level = level;

			var delta = level - oldLevel;

			values.hpMax += (40 * delta);

			syncer.setObject(true, 'stats', 'values', 'level', level);
			syncer.setObject(true, 'stats', 'values', 'hpMax', values.hpMax);

			process.send({
				method: 'object',
				serverId: obj.serverId,
				obj: {
					level: level
				}
			});

			stats.calcXpMax();
		},

		godMode: function () {
			var obj = this.obj;

			var statValues = obj.stats.values;
			var newValues = {
				int: 10000000,
				str: 10000000,
				dex: 10000000,
				hpMax: 10000000,
				hp: 10000000,
				manaMax: 10000000,
				mana: 10000000,
				sprintChance: 100,
				vit: 10000000
			};

			var syncer = obj.syncer;

			for (var s in newValues) {
				var newValue = newValues[s];
				statValues[s] = newValue;

				syncer.setObject(true, 'stats', 'values', s, newValue);
			}

			obj.spellbook.calcDps();
		},

		completeQuests: function () {
			var obj = this.obj;
			var quests = obj.quests;

			quests.quests.forEach(function (q) {
				q.isReady = true;
				q.complete();
			}, this);

			quests.quests = [];
			obj.instance.questBuilder.obtain(obj);
		},

		getReputation: function (faction) {
			if (typeof (faction) != 'string')
				return;

			this.obj.reputation.getReputation(faction, 50000);
		},

		loseReputation: function (faction) {
			if (typeof (faction) != 'string')
				return;

			this.obj.reputation.getReputation(faction, -50000);
		},

		setStat: function (config) {
			this.obj.stats.values[config.stat] = ~~config.value;
		},

		getXp: function (amount) {
			this.obj.stats.getXp(amount, this.obj, this.obj);
		},

		die: function () {
			this.obj.stats.takeDamage({
				amount: 99999
			}, 1, this.obj);
		}
	};
});
