/**
 * widgetBuildsCtrl Controller
 * Extracted from bookings module
 */

Bookings.controller('widgetBuildsCtrl', ['$scope', 'BuildsService', 'Build', 'ErrorsHandler', '$timeout', '$q', 'Messenger', '$uibModal', 'Part', 'PartsService', function ($scope, BuildsService, Build, ErrorsHandler, $timeout, $q, Messenger, $uibModal, Part, PartsService) {

	/**
	 * List of builds
	 *
	 * @array
	 */
	$scope.builds = BuildsService.builds;


	/**
	 * Update the factory with the builds, when the related object
	 * is available. (related can be either a task or an order)
	 */
	$scope.$watch('related', function (related) {
		if (related)
			BuildsService.setBuilds(related.builds);
	}, true);


	/**
	 * Update the pricing table when the builds list change
	 */
	$scope.$watch('builds', function () {
		$scope.buildTotal();
		BuildsService.setSubtotal($scope.subtotal());
		BuildsService.setTax($scope.tax());
		BuildsService.setTotal(BuildsService.getSubtotal() + BuildsService.getTax());
	}, true);


	/**
	 * Stores a new build.
	 *
	 * @param  ev $event
	 * @param  object data - build data
	 * @return void
	 */
	$scope.addBuild = function (ev, data) {

		var build = _.find($scope.builds, function (el) {
			if (el.stock)
				return el.stock.id == data.id && el.status == 'planning';
			return false;
		});

		$scope.$apply(function () {


			if (build) {
				build.quantity++;
				$scope.updateBuild(build);

			} else {

				Build.save({
					related_id: $scope.related.id,
					related_type: $scope.related_type,
					stock_id: data.id,
					quantity: 1,
					price: data.price_excluding_vat
				}, function (res) {

					$scope.builds.push(res);
					if ($scope.related_type == 'user')
						$scope.related.builds.push(res);

				}, function (response, b) {
					// Handle the specific error format from BuildsController
					if (response.data && response.data.error) {
						alert('BUILD ERROR: ' + response.data.error); // Temporary debugging
						Messenger(response.data.error, 'error');
					} else if (response.data && response.data.success === false && response.data.message) {
						alert('BUILD MESSAGE: ' + response.data.message); // Temporary debugging
						Messenger(response.data.message, 'error');  
					} else {
						alert('OTHER ERROR: ' + JSON.stringify(response.data)); // Temporary debugging
						ErrorsHandler(response, b);
					}
					return false;
				});
			}
		});

	};


	/**
	 * Removes a build from the build list.
	 *
	 * @param  object  The build to be removed
	 * @return void
	 */
	$scope.removeBuild = function (build) {

		Build.remove({ buildId: build.id }, function () {
			var index = _.findIndex($scope.builds, function (el) {
				return el.id === build.id;
			});

			$scope.builds.splice(index, 1);

			if ($scope.related_type == 'user')
				$scope.related.builds.splice(index, 1);

		}, ErrorsHandler);
	};

	/**
	 * Updates an existing build.
	 *
	 * @return void
	 */
	$scope.updateBuild = function (build) {

		Build.update(build, function (response) {
			build.saved = true;
			// build.updated_at = response.updated_at;
			angular.extend(build, response || {});
		}, function (a, b) {
			build.failed = true;
			ErrorsHandler(a, b);
		});

		$timeout(function () {
			build.saved = false;
			build.failed = false;
		}, 1500);
	};

	/**
	 * Update a single property of a build
	 *
	 * @param  object build
	 * @param  string property
	 * @param  mixed value
	 * @return null
	 */
	$scope.updateBuildProperty = function (build, property, value) {

		var deferred = $q.defer();
		var data = {
			id: build.id,
			updated_at: build.updated_at,
		};

		// Build the data object
		data[property] = value;

		Build.update(data, function (response) {
			angular.extend(build, response || {});
			deferred.resolve(true);

		}, function (a, b) {

			ErrorsHandler(a, b);
			deferred.reject(false);
		});

		return deferred.promise;
	};


	/**
	 * Update the build status to completed and add the composite
	 * stock as a part.
	 *
	 * @param  object build
	 * @param  bool   attach_to_parts
	 * @return null
	 */
	$scope.completeBuild = function (build, attach_to_parts) {
		build.status = 'completed';

		Build.update(build, function (response) {

			// If there is another build completed and using the same stock template merge them.
			var oldIndex = _.findIndex($scope.builds, function (el) {
				return el.id === response.id;
			});
			if (oldIndex)
				$scope.builds.splice(oldIndex, 1);

			var oldBuild = angular.copy(build);
			angular.extend(build, response || {});

			if (attach_to_parts) {
				var part = _.find(PartsService.parts, function (el) { return el.stock_id === build.stock_id; });

				if (part) {
					part.quantity += oldBuild.quantity;
					Part.save(part, function (res) {
						PartsService.addPart(res);
					}, function (a, b) {
						ErrorsHandler(a, b);
						return false;
					});

				} else {
					part = {
						related_id: $scope.related.id,
						related_type: $scope.related_type,
						stock_id: build.stock_id,
						quantity: build.quantity,
						price: build.stock.price_excluding_vat
					};
					Part.save(part, function (res) {
						PartsService.addPart(res);
					}, function (a, b) {
						ErrorsHandler(a, b);
						return false;
					});
				}


			}

			return true;

		}, function (a, b) {
			build.status = 'in_progress';
			ErrorsHandler(a, b);
		});

	}


	/**
	 * Update the price per unit from the total price given.
	 *
	 * @param  mixed  value
	 * @param  object build
	 * @return null
	 */
	$scope.updateTotalPrice = function (value, build) {

		if (isNaN(value)) {
			alert("The total price given is not a valid price.");
			return;
		}

		$scope.updateBuildProperty(build, 'price', (build.total_price / build.quantity / ($scope.vat / 100 + 1)).toFixed(2));
	};

	/**
	 * Calcualate the total price for each individual build
	 * @return {[type]} [description]
	 */
	$scope.buildTotal = function () {
		_.each($scope.builds, function (build) {
			build.total_price = build.price * build.quantity * ($scope.vat / 100 + 1);
		});
	};

	/**
	 * Calculates the total price for builds.
	 *
	 * @return float
	 */
	$scope.total = function () {
		return $scope.subtotal() + $scope.tax();
	};

	/**
	 * Calculates the total tax for builds.
	 *
	 * @return float
	 */
	$scope.tax = function () {
		var tax = 0;

		_.each($scope.builds, function (el) { tax += el.price * el.quantity * $scope.vat / 100; });

		return tax;
	};

	/**
	 * Calculates the total for the builds, excluding tax.
	 *
	 * @return float
	 */
	$scope.subtotal = function () {
		var total = 0;

		_.each($scope.builds, function (el) { total += el.price * el.quantity; });

		return total;
	};

	/**
	 * Calculates the total for the parts, excluding tax.
	 *
	 * @return float
	 */
	$scope.cost = function () {

		var cost = 0;
		_.each($scope.builds, function (el) {
			cost += el.cost * el.quantity;
		});

		return cost;
	};

	/**
	 * Open a popup with the list components used in this build.
	 *
	 * @param  object build
	 * @return null
	 */
	$scope.showBuildComponents = function (build) {

		var modalInstance = $uibModal.open({
			controller: 'BuildCompositeItemsCtrl',
			templateUrl: 'bookings/modals/build-composite-items.html',
			resolve: {
				build: function () {
					return build;
				}
			}
		});

		modalInstance.result.then(function (data) {
			angular.extend(build, data || {});
		});
	};


}])
