(function($) {

    'use strict';

    var site;

    var highlight = function(text, part) {
        text = text.replace(new RegExp('('+ part +')', 'ig'), '<strong>$1</strong>');

        return text;
    };

    var hideResults = function() {
        $('.search-results').hide();
    };

    var showResults = function(q, results) {
        var $results = $('.search-results'),
            $resultsCount = $('.search-results-count', $results),
            $resultList = $('.dropdown-menu', $results),
            totalScore = 0;

        $results.show();

        // Show how many results there were, in the DOM.
        $resultsCount.text(results.total + (results.total === 1 ? ' result' : ' results'));

        // Get the total score of all items, so that we can divide each result into it, giving us a percentage
        $.each(results, function(i, result) {
            totalScore += result.score;
        });

        // Append each result link, with a border that corresponds to a color with a strength equal to its percentage
        // of the total score
        $resultList.empty();
        $resultList.removeClass('show');

        if (results.total > 0) {
            $.each(results.categories, function(category, categoryResults) {
                var categoryLabel = category.replace(new RegExp('-', 'g'), ' ').toUpperCase();

                var $category = $('<h6 class="dropdown-header">'+ categoryLabel +'</h6>');

                $resultList.append($category);
                var itemAdded = false;

                for (var i = 0; i < categoryResults.length; i++) {
                    var url      = site + categoryResults[i].ref;
                    var title    = categoryResults[i].title;
                    var content  = categoryResults[i].content;

                    var searchRegExp = new RegExp(q, 'i');
                    var foundIndex;

                    // Title contains query phrase?
                    if (-1 !== title.search(searchRegExp)) {
                        title = highlight(title, q);

                        $resultList.append('<a class="dropdown-item" href="' + url + '">' + title + '</a>');

                        itemAdded = true;
                    // Content contains it?
                    } else if ( -1 !== ( foundIndex = content.search(searchRegExp) ) ) {
                        var contentPart = '';

                        var startIndex = foundIndex - 35 >= 0 ? foundIndex - 35 : 0;
                        var length = 70;

                        contentPart = content.substr(startIndex, length);

                        // Get rid of partial words.
                        contentPart = '...' + contentPart.replace(/^[^\s]*\s/, ''); // Remove first word (partial or not) from the beginning.
                        contentPart = contentPart.replace(/\s[^\s]*$/, '') + '...'; // Remove last word (partial or not) from the end.

                        contentPart = highlight(contentPart, q);

                        $resultList.append('<a class="dropdown-item" href="' + url + '">' + title + '<div>'+ contentPart +'</div></a>');

                        itemAdded = true;
                    }
                }

                if (!itemAdded) {
                    $category.remove();
                }
            });

            $resultList.addClass('show');
        }
    };

    var init = function() {
        site = location.protocol + "//" + location.host;

        // Load dictionary.
        $.ajax({
            url: '/posts.json',
            dataType: 'json'
        }).done(function(data) {
            var searchIndex,
                results,
                highScoredResults,
                $searchInput = $('#search-input');

            // Set up index.
            searchIndex = lunr(function() {
                this.field('title');
                this.field('category');
                this.field('content');
                this.ref('url');
                this.field('date');

                data.forEach(function (doc) {
                    this.add(doc)
                }, this)
            });

            // Block enter.
            $searchInput.on('keydown', function(e) {
                if(e.keyCode === 13) {
                    e.preventDefault();
                    return false;
                }
            });

            $searchInput.on('input', function() {
                var q = $(this).val();

                if (q.length < 2) {
                    hideResults();
                    return;
                }

                // q.term(word, { boost: 100 }) // large boost exact match
                // q.term(word, { boost: 10, wildcard: lunr.Query.wildcard.TRAILING, usePipeline: false }) // small boost for prefix match
                // q.term(word, { boost: 1, editDistance: 1, usePipeline: false }) // no boost for fuzzy match
                // Equal to '${word}^100 ${word}*^10 ${word}~1^1'
                // ${word}^100 - large boost exact match
                // ${word}*^10 - small boost for prefix match
                // ${word}~1^1 - // no boost for fuzzy match
                results = searchIndex.search(q + '^100 ' + q + '*^10 ' + q + '~1^1');

                highScoredResults = {
                    total:      0,
                    categories: {}
                };

                // Add the title and category of each post into each result, too (this doesn't come standard with lunr.js).
                for(var index in results) {
                    var result = results[index];

                    if (index < 5) {
                        highScoredResults.total++;

                        var match = data.filter(function(post) {
                            return post.url === result.ref;
                        });

                        result.title = match[0].title;
                        result.content = match[0].content;
                        var category = match[0].category;

                        if (!highScoredResults.categories[category]) {
                            highScoredResults.categories[category] = [];
                        }

                        highScoredResults.categories[category].push(result);
                    }
                }

                showResults(q, highScoredResults);
            });
        });
    };

    $(document).ready(function() {
        init();
    });

})(jQuery);