'use strict';


define('search', ['navigator', 'translator', 'storage', 'hooks'], function (nav, translator, storage, hooks) {
	var Search = {
		current: {},
	};

	Search.query = function (data, callback) {
		// Detect if a tid was specified
		var topicSearch = data.term.match(/^in:topic-([\d]+) /);
		callback = callback || function () {};
		if (!topicSearch) {
			ajaxify.go('search?' + createQueryString(data));
			callback();
		} else {
			var cleanedTerm = data.term.replace(topicSearch[0], '');
			var tid = topicSearch[1];

			if (cleanedTerm.length > 0) {
				Search.queryTopic(tid, cleanedTerm, callback);
			}
		}
	};

	Search.api = function (data, callback) {
		var apiURL = config.relative_path + '/api/search?' + createQueryString(data);
		data.searchOnly = undefined;
		var searchURL = config.relative_path + '/search?' + createQueryString(data);
		$.get(apiURL, function (result) {
			result.url = searchURL;
			callback(result);
		});
	};

	function createQueryString(data) {
		var searchIn = data.in || 'titles';
		var postedBy = data.by || '';
		var term = data.term.replace(/^[ ?#]*/, '');
		try {
			term = encodeURIComponent(term);
		} catch (e) {
			return app.alertError('[[error:invalid-search-term]]');
		}

		var query = {
			term: term,
			in: searchIn,
		};

		if (data.matchWords) {
			query.matchWords = data.matchWords;
		}

		if (postedBy && postedBy.length && (searchIn === 'posts' || searchIn === 'titles' || searchIn === 'titlesposts')) {
			query.by = postedBy;
		}

		if (data.categories && data.categories.length) {
			query.categories = data.categories;
			if (data.searchChildren) {
				query.searchChildren = data.searchChildren;
			}
		}

		if (data.hasTags && data.hasTags.length) {
			query.hasTags = data.hasTags;
		}

		if (parseInt(data.replies, 10) > 0) {
			query.replies = data.replies;
			query.repliesFilter = data.repliesFilter || 'atleast';
		}

		if (data.timeRange) {
			query.timeRange = data.timeRange;
			query.timeFilter = data.timeFilter || 'newer';
		}

		if (data.sortBy) {
			query.sortBy = data.sortBy;
			query.sortDirection = data.sortDirection;
		}

		if (data.showAs) {
			query.showAs = data.showAs;
		}

		if (data.searchOnly) {
			query.searchOnly = data.searchOnly;
		}

		hooks.fire('action:search.createQueryString', {
			query: query,
			data: data,
		});

		return decodeURIComponent($.param(query));
	}

	Search.getSearchPreferences = function () {
		try {
			return JSON.parse(storage.getItem('search-preferences') || '{}');
		} catch (e) {
			return {};
		}
	};

	Search.highlightMatches = function (searchQuery, els) {
		if (!searchQuery || !els.length) {
			return;
		}
		searchQuery = utils.escapeHTML(searchQuery.replace(/^"/, '').replace(/"$/, '').trim());
		var regexStr = searchQuery.split(' ')
			.map(function (word) { return utils.escapeRegexChars(word); })
			.join('|');
		var regex = new RegExp('(' + regexStr + ')', 'gi');

		els.each(function () {
			var result = $(this);
			var nested = [];

			result.find('*').each(function () {
				$(this).after('<!-- ' + nested.length + ' -->');
				nested.push($('<div></div>').append($(this)));
			});

			result.html(result.html().replace(regex, function (match, p1) {
				return '<strong class="search-match">' + p1 + '</strong>';
			}));

			nested.forEach(function (nestedEl, i) {
				result.html(result.html().replace('<!-- ' + i + ' -->', function () {
					return nestedEl.html();
				}));
			});
		});

		$('.search-result-text').find('img:not(.not-responsive)').addClass('img-responsive');
	};

	Search.queryTopic = function (tid, term) {
		socket.emit('topics.search', {
			tid: tid,
			term: term,
		}, function (err, pids) {
			if (err) {
				return app.alertError(err.message);
			}

			if (Array.isArray(pids)) {
				// Sort pids numerically & store
				Search.current = {
					results: pids.sort(function (a, b) {
						return a - b;
					}),
					tid: tid,
					term: term,
				};

				Search.checkPagePresence(tid, function () {
					Search.topicDOM.update(0);
				});
			}
		});
	};

	Search.checkPagePresence = function (tid, callback) {
		if (parseInt(ajaxify.data.tid, 10) !== parseInt(tid, 10)) {
			ajaxify.go('topic/' + tid, callback);
		} else {
			callback();
		}
	};

	Search.topicDOM = {
		active: false,
	};

	Search.topicDOM.prev = function () {
		Search.topicDOM.update((Search.current.index === 0) ? Search.current.results.length - 1 : Search.current.index - 1);
	};

	Search.topicDOM.next = function () {
		Search.topicDOM.update((Search.current.index === Search.current.results.length - 1) ? 0 : Search.current.index + 1);
	};

	Search.topicDOM.update = function (index) {
		var topicSearchEl = $('.topic-search');
		Search.current.index = index;

		Search.topicDOM.start();

		if (Search.current.results.length > 0) {
			topicSearchEl.find('.count').html((index + 1) + ' / ' + Search.current.results.length);
			topicSearchEl.find('.prev, .next').removeAttr('disabled');
			var data = {
				pid: Search.current.results[index],
				tid: Search.current.tid,
				topicPostSort: config.topicPostSort,
			};
			socket.emit('posts.getPidIndex', data, function (err, postIndex) {
				if (err) {
					return app.alertError(err.message);
				}

				nav.scrollToIndex(postIndex, true);
			});
		} else {
			translator.translate('[[search:no-matches]]', function (text) {
				topicSearchEl.find('.count').html(text);
			});
			topicSearchEl.removeClass('hidden').find('.prev, .next').attr('disabled', 'disabled');
		}
	};

	Search.topicDOM.start = function () {
		$('.topic-search').removeClass('hidden');
		if (!Search.topicDOM.active) {
			Search.topicDOM.active = true;

			// Bind to esc
			require(['mousetrap'], function (mousetrap) {
				mousetrap.bind('esc', Search.topicDOM.end);
			});
		}
	};

	Search.topicDOM.end = function () {
		$('.topic-search').addClass('hidden').find('.prev, .next').attr('disabled', 'disabled');
		Search.topicDOM.active = false;

		// Unbind esc
		require(['mousetrap'], function (mousetrap) {
			mousetrap.unbind('esc', Search.topicDOM.end);
		});
	};

	return Search;
});
