export default class QualitycheckController {



    constructor($scope, $q, $log, $rootScope, TextReview, RawTextReview, ProductResource) {
        'ngInject';
        this.$scope = $scope;
		this.$q = $q;
		this.$log = $log;
		this.$rootScope = $rootScope;
		this.TextReview = TextReview;
        this.RawTextReview = RawTextReview;
        this.ProductResource = ProductResource;
		this.buildQualityCheckRunners();
    }

    $onInit() {
		this.loadData();
		this.dataFromQualityCheckOnRawTextReviews = [];
		this.dataFromQualityCheckOnAnalyzedReviews = [];

		this.currentQueryForRawTextReviews = null;
		this.currentQueryForAnalyzedReviews = null;

		this.isQualityCheckUpdating = false;
		this.bindEvents();


    }

	bindEvents() {
		this.$rootScope.$on('ProductFilter.filterByProduct',  (e, product) => {
			this.currentQueryForRawTextReviews = {
				'title': {
					$in: product.reviewTitles || []
				}
			};
			this.currentQueryForAnalyzedReviews = {
				'review.title': {
					$in: product.reviewTitles || []
				}
			};
			this.loadData();
		});
		this.$rootScope.$on('ProductFilter.removeCurrentFilter',  () => {
			this.currentQueryForAnalyzedReviews = null;
			this.currentQueryForRawTextReviews = null;
			this.loadData();
		});
	}

	buildQualityCheckRunners(){

		function QualityCheckRunner(opts) {
			opts = opts || {};
			this.api = opts.api || null;
			this.apiName = opts.apiName || null;
			this.isNullValue = opts.isNullValue || [];
			this.isLongerThan = opts.isLongerThan || [];
			this.isGreaterThan = opts.isGreaterThan || [];
			this.isLessThan = opts.isLessThan || [];
			this.isType = opts.isType || [];
			if (!this.api) {
				throw new Error('Please provide an API object');
			}
		}

		QualityCheckRunner.prototype._enrichQuery = function(query) {
			var serviceName, tmp, tmp2, fieldName, enrichingParametersName;

			$log.info('>>>> Enriching Query!');

			serviceName = this.apiName;
			fieldName = (serviceName === 'RawTextReview') ? 'title' : 'review.title';
			enrichingParametersName = (serviceName === 'RawTextReview') ? 'currentQueryForRawTextReviews' : 'currentQueryForAnalyzedReviews';
			if (!$scope[enrichingParametersName]) {
				return query;
			}
			if (typeof query[fieldName] !== 'undefined') {
				tmp = angular.copy(query[fieldName]);
				delete query[fieldName];
				query['+$and'] = [];
				tmp2 = {};
				tmp2[fieldName] = tmp;
				query['+$and'].push(tmp2);
				tmp2 = {};
				tmp2[fieldName] = $scope[enrichingParametersName].title;
				query['+$and'].push(tmp2);
			} else {
				query[fieldName] = $scope[enrichingParametersName][fieldName];
			}
			return query;
		};

		QualityCheckRunner.prototype.run = function() {
			var result = [];
			return $q.all([
				this.countReviewsWithoutFieldByFieldName(),
				this.countReviewsWhoseFieldIsLongerThanExpected(),
				this.countReviewsWhoseFieldIsGreaterThanExpected(),
				this.countReviewsWhoseFieldIsLessThanExpected(),
				this.countReviewsWhoseFieldHaveDifferentTypeThanExpected()
			]).then(function(res) {
				res.forEach(function(arr) {
					arr.filter(function(el) {
						return el !== null && typeof el !== 'undefined';
					}).forEach(function(el) {
						result.push(el);
					});
				});
				$log.info('>>>> QualityChecker: Result', result);
				return result;
			});
		};

		QualityCheckRunner.prototype.countReviewsWithoutFieldByFieldName = function() {
			var promises;
			var self = this;
			promises = this.isNullValue.map(function(fieldName) {
				var query = {};
				query[fieldName] = null;
				query = self._enrichQuery(query);
				$log.info('>>> Query is', query);
				return self.api.count(query)
					.then(function(count) {
						count = parseInt(count.replace(/"/gi, ''));
						if (count === 0 || isNaN(count)) {
							return null;
						}
						return {
							type: 'has "null" as value',
							fieldName: fieldName,
							numberOfReviews: count,
							query: query
						};
					});
			});
			return $q.all(promises);
		};

		QualityCheckRunner.prototype.countReviewsWhoseFieldIsLongerThanExpected = function() {
			var self = this;
			var promises;
			promises = this.isLongerThan.map(function(field) {
				var maxLength = field.maxLength;
				var fieldName = field.fieldName;
				var query = {};
				query['+$where'] = 'return this.' + fieldName + ' && this.' + fieldName + '.length > ' + maxLength;
				query = self._enrichQuery(query);
				$log.info('>>> Query is', query);
				return self.api.count(query)
					.then(function(count) {
						count = parseInt(count.replace(/"/gi, ''));
						if (count === 0 || isNaN(count)) {
							return null;
						}
						return {
							type: 'is longer than ' + maxLength,
							fieldName: fieldName,
							numberOfReviews: count,
							query: query
						};
					});
			});
			return $q.all(promises);
		};

		QualityCheckRunner.prototype.countReviewsWhoseFieldIsGreaterThanExpected = function() {
			var self = this;
			var promises;
			promises = this.isGreaterThan.map(function(field) {
				var upperBound = field.upperBound;
				var fieldName = field.fieldName;
				var query = {};
				query[fieldName] = {
					'+$gt': upperBound
				};
				query = self._enrichQuery(query);
				$log.info('>>> Query is', query);
				return self.api.count(query)
					.then(function(count) {
						count = parseInt(count.replace(/"/gi, ''));
						if (count === 0 || isNaN(count)) {
							return null;
						}
						return {
							type: 'greater than ' + upperBound,
							fieldName: fieldName,
							numberOfReviews: count,
							query: query

						};
					});
			});
			return $q.all(promises);
		};

		QualityCheckRunner.prototype.countReviewsWhoseFieldIsLessThanExpected = function() {
			var self = this;
			var promises;
			promises = this.isLessThan.map(function(field) {
				var lowerBound = field.lowerBound;
				var fieldName = field.fieldName;
				var query = {};
				query[fieldName] = {
					'+$lt': lowerBound
				};
				query = self._enrichQuery(query);
				$log.info('>>> Query is', query);
				return self.api.count(query)
					.then(function(count) {
						count = parseInt(count.replace(/"/gi, ''));
						if (count === 0 || isNaN(count)) {
							return null;
						}
						return {
							type: 'is less than ' + lowerBound,
							fieldName: fieldName,
							numberOfReviews: count,
							query: query
						};
					});
			});
			return $q.all(promises);
		};

		QualityCheckRunner.prototype.countReviewsWhoseFieldHaveDifferentTypeThanExpected = function() {
			var self = this;
			var promises;
			promises = this.isType.map(function(field) {
				var expectedType = field.expectedType;
				var fieldName = field.fieldName;
				var query = {};
				query['+$where'] = 'return this.' + fieldName + ' && !(this.' + fieldName + ' instanceof ' + expectedType + ')';
				query = self._enrichQuery(query);
				$log.info('>>> Query is', query);
				return self.api.count(query)
					.then(function(count) {
						count = parseInt(count.replace(/"/gi, ''));
						if (count === 0 || isNaN(count)) {
							return null;
						}
						return {
							type: 'has wrong type',
							fieldName: fieldName,
							numberOfReviews: count,
							query: query
						};
					});
			});
			return $q.all(promises);
		};

		this.q1 = new QualityCheckRunner({
			api: RawTextReview,
			apiName: 'RawTextReview',
			isNullValue: ['pubDate', 'country', 'channel', 'title', 'subtitle','translation'],
			isLongerThan: [{
				fieldName: 'authorName',
				maxLength: 113
			}],
			isGreaterThan: [{
				fieldName: 'pubDate',
				upperBound: 'ISODate(\'' + new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate(), 14, 0).toISOString() + '\')'
			}],
			isLessThan: [{
				fieldName: 'pubDate',
				lowerBound: 'ISODate(\'' + new Date(1995, 1, 1).toISOString() + '\')'
			}],
			isType: [{
				fieldName: 'pubDate',
				expectedType: 'Date'
			}]
		});
		this.q2 = new QualityCheckRunner({
			api: TextReview,
			apiName: 'TextReview',
			qualityCheckRunnersSettings: $scope.qualityCheckRunnersSettings,
			isNullValue: ['review.pubDate', 'review.country', 'review.channel', 'review.title', 'review.subtitle','review.translation'],
			isLongerThan: [{
				fieldName: 'review.authorName',
				maxLength: 113
			}],
			isGreaterThan: [{
				fieldName: 'review.pubDate',
				upperBound: 'ISODate(\'' + new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate(), 14, 0).toISOString() + '\')'
			}],
			isLessThan: [{
				fieldName: 'review.pubDate',
				lowerBound: 'ISODate(\'' + new Date(1995, 1, 1).toISOString() + '\')'
			}],
			isType: [{
				fieldName: 'review.pubDate',
				expectedType: 'Date'
			}]
		});
	}

	loadData() {
		if ($scope.currentQueryForAnalyzedReviews===null && $scope.currentQueryForRawTextReviews===null){
			return;
		}
		this.isQualityCheckUpdating = true;
		this.$q.all([ this.q1.run(), this.q2.run()])
			.then( (res) => {
				this.$log.info('>>> Result - RawReviews', res[0]);
				this.dataFromQualityCheckOnRawTextReviews = res[0];
				this.$log.info('>>> Result - Analyzed Reviews', res[1]);
				this.dataFromQualityCheckOnAnalyzedReviews = res[1];
			})
			.catch( (msg) => {
				return alert('Error: ' + msg);
			})
			.finally( () => {
				this.isQualityCheckUpdating = false;
			});
	}


	showProductNamesByIssue(issue, areRawTextReviews) {
		var promise, query;
		query = issue.query;
		this.issueRelatedProducts = null;

		if (areRawTextReviews) {
			promise = this.RawTextReview.distinct('title', query);
		} else {
			promise = this.TextReview.distinct('review.title', query);
		}

		promise
		.then( (reviewTitles) => {
			return this.ProductResource.queryAllByReviewTitles(reviewTitles);
		})
		.then( (products) => {
			var list;
			list = products.map( (el) => {
				return el.brandName + ' - ' + el.productName;
			}).sort( (e1, e2) => {
				return e1 < e2;
			});
			if (list.length > 0) {
				list = list.join('\n');
			} else {
				list = 'None';
			}
			alert(list);
		})
		.catch( (msg) => {
			alert('Error:', msg);
		});

	};

}

