define([
	],
	function() {
		var dataController = function(
			$scope,
			$q,
			$timeout,
			hosts,
			health,
			redis,
			rings,
			RING_TYPES,
			CENTRAL_API_URL
		) {
			var self = this;
			this.isUndefined = _.isUndefined;
			this.min = _.min;
			this.round = Math.round;
			this.size = _.size;
			var nameMap;

			this.rings = _.chain(RING_TYPES)
				.map(function(type) {
					return [type, {}]
				})
				.object()
				.value();

			this.getUtil = function(group) {
				return function(item) {
					return -1 * self.health[group].servers[item.ip].percent_used
				}
			}

			this.refreshRings = function(reschedule) {
				var promises = _.map(RING_TYPES, function(type) {
					return rings.setEndpoint(([
						// CENTRAL_API_URL,
						// 'swift',
						'/swift',
						type
					]).join('/'))
					.get().then(function(result) {
						self.rings[type].id = _.chain(result.data.devices)
							.map(function(obj) {
								return [
									obj.id,
									_.pick(obj, [
										'ip',
										'weight',
										'device',
										'id'
									])
								]
							})
							.object()
							.value()
						self.rings[type].uuid = _.chain(result.data.devices)
							.map(function(obj) {
								return [
									obj.device,
									_.pick(obj, [
										'ip',
										'weight',
										'device',
										'id'
									])
								]
							})
							.object()
							.value()
					})
				})

				if(reschedule) {
					$timeout(function() {
						self.refreshRings(true);
					}, 5 * 60 * 1000)
				}

				return $q.all(promises);
			}

			this.refreshRedis = function(reschedule) {
				var promise = redis.get().then(function(progress) {
					var results = progress.data
					var temp = []

					_.each(RING_TYPES, function(type) {
						temp = temp.concat(
							_.map(results.add_devices[type], function(device) {
								return {
									type: 'ADD',
									host: device.host,
									stage: device.stage,
									drive: device.drive,
									ring: type,
									hash: 'add-' + device.host + '-' + device.type + '-' + device.drive,
								}
							}),
							_.sortByOrder(_.chain(results.weight_targets[type])
								.pick(function(target, id) {
									return !_.isUndefined(self.rings[type].id[id])
								})
								.map(function(target, id) {
									return {
										type: 'REWEIGHT',
										id: id,
										host: nameMap[self.rings[type].id[id].ip + ':8082'],
										ring: type,
										target: target,
										hash: 'reweight-' + type + '-' + id,
									}
								})
								.value().concat(_.chain(results.remove_devices[type])
									.pick(function(val, id) {
										return !_.isUndefined(self.rings[type].id[id])
									})
									.map(function(val, id) {
										return {
											type: 'DELETE',
											id: id,
											host: nameMap[self.rings[type].id[id].ip + ':8082'],
											ring: type,
											hash: 'delete-' + type + '-' + id,
										}
									})
									.value()),
								['id', 'type'],
								['asc', 'desc']
							)
						)
					})

					self.inProgress = _.chain(temp)
						.groupBy(function(drive) {
							return drive.host;
						})
						.map(function(group, name) {
							return {
								name: name,
								reweight: _.filter(group, function(drive) {
									return drive.type === 'REWEIGHT'
								}).length,
								deleting: _.filter(group, function(drive) {
									return drive.type === 'DELETE'
								}).length,
								pending: _.filter(group, function(drive) {
									return drive.type === 'ADD' && drive.stage === 'PENDING'
								}).length,
								prepping: _.filter(group, function(drive) {
									return drive.type === 'ADD' && drive.stage === 'PREP'
								}).length,
								adding: _.filter(group, function(drive) {
									return drive.type === 'ADD' && drive.stage === 'ADD'
								}).length,
								formatting: _.filter(group, function(drive) {
									return drive.type === 'ADD' && drive.stage === 'FORMAT'
								}).length,
								children: group
							}
						})
						.value()

					self.redis = results;
				})

				if(reschedule) {
					$timeout(function() {
						self.refreshRedis(true);
					}, 60 * 1000)
				}

				return promise;
			}

			this.refreshHealth = function(reschedule) {
				var promise = health.get().then(function(health) {
					self.unhealthy = []
					var results = health.data

					_.each(RING_TYPES, function(type) {
						_.each(results[type].servers, function(host, ip) {
							self.unhealthy = self.unhealthy.concat(_.map(host.unhealthy_devices, function(host) {
								return {
									type: 'DEVICE',
									group: type,
									host: ip,
									drive: host.drive,
									uuid: host.uuid
								}
							}))

							host.unhealthy_devices = _.indexBy(host.unhealthy_devices, 'uuid')
						})
					})

					results.bad_hosts = _.chain(results.bad_hosts)
						.map(function(host) {
							return [host, true];
						})
						.object()
						.value()

					self.unhealthy = self.unhealthy.concat(_.map(results.bad_hosts, function(value, host) {
						return {
							type: 'HOST',
							name: host,
						}
					}))

					self.health = results;
				})

				if(reschedule) {
					$timeout(function() {
						self.refreshHealth(true);
					}, 60 * 1000)
				}

				return promise;
			}

			self.initialized = $q.all([
				hosts.get(),
				health.get(),
				$q.all(_.map(RING_TYPES, function(type) {
					return rings.setEndpoint(([
						// CENTRAL_API_URL,
						// 'swift',
						'/swift',
						type
					]).join('/'))
					.get()
				}))
			]).then(function(results) {
				var hosts = results[0].data;
				var health = results[1].data;
				var rings = _.chain(RING_TYPES)
					.map(function(ring, idx) {
						return [ring, _.get(results[2][idx], 'data.devices')]
					})
					.object()
					.value()

				nameMap = _.invert(hosts);

				var ungrouped = {
					type: 'uninitialized',
					hosts: _.chain(hosts)
						.values()
						.difference(
							_.chain(RING_TYPES)
								.map(function(type) {
									return _.chain(rings[type])
										.values()
										.map(function(value) {
											return value.ip + ':8082'
										})
										.uniq(false)
										.value()
								})
								.flatten()
								.uniq(false)
								.value())
						.map(function(ip) {
							return {
								ip: ip,
								name: nameMap[ip.toString()]
							}
						})
						.sortByOrder([
								'name'
							],
							['asc'])
						.value()
				}

				self.health = health;
				self.groups = _.chain(RING_TYPES)
					.map(function(type) {
						var group = {
							type: type,
							hosts: _.chain(rings[type])
								.values()
								.pluck('ip')
								.uniq(false)
								.map(function(ip) {
									var long = ip + ':8082';
									return {
										ip: long,
										name: nameMap[long]
									}
								})
								.sortByOrder([
									'name'
								],
								['asc'])
								.value()
						}

						return group
					})
					.value()
					.concat([ungrouped]);

				_.each(RING_TYPES, function(type) {
					health[type].summary.percent_used = 0;
					health[type].summary.used_space_TB = 0;

					_.each(health[type].servers, function(host, ip) {
						host.percent_used = 0;
						host.used_space_TB = 0;
					})
				})

				return $q.all([
					self.refreshHealth(true),
					self.refreshRings(true)
				])
			}).then(function() {
				return self.refreshRedis(true);
			})
		}

		return dataController;
	}
)