/**
 * @namespace WORKAREA.bulkActionItems
 */
WORKAREA.registerModule('bulkActionItems', (function () {
    'use strict';

    var hiddenInput = JST['workarea/core/templates/hidden_input'],
        countUI = JST['workarea/admin/templates/bulk_action_items_count'],

        storage = window.sessionStorage,


        //
        // Utility
        buildInputGroup = function (collection, group) {
            return _.map(collection, function (value) {
                var result = hiddenInput({ name: group + '[]', value: value });
                return $(result).data('addedByBulkActionItem', true);
            });
        },


        //
        // Session
        removeSession = function () {
            storage.removeItem('bulkActionItems');
        },

        setSession = function (state) {
            storage.setItem('bulkActionItems', JSON.stringify(state));
        },

        /**
         * @method
         * @name getSession
         * @memberof WORKAREA.bulkActionItems
         */
        getSession = function () {
            return JSON.parse(storage.getItem('bulkActionItems'));
        },

        initSession = _.once(setSession),

        setup = function ($scope) {
            var state = {}, initialCount;

            initialCount = $('[data-browsing-controls-count]', $scope).data(
                'browsingControlsCount'
            );

            state.ids = [];
            state.count = 0;
            state.excludeIds = [];
            state.includeAll = false;
            state.pathname = window.location.pathname;
            state.initialCount = initialCount;
            initSession(state);

            return state;
        },

        sessionApplicable = function () {
            var session = getSession();
            return session && session.pathname === window.location.pathname;
        },


        //
        // State Management
        toggleSelectAll = function (scope, session) {
            var $selectAll = $('[data-bulk-action-select-all]', scope),
                $selectAllCheckbox = $selectAll.closest('.checkbox'),
                allSelected = session.count === session.initialCount;

            if (allSelected) {
                $selectAll.prop('checked', true);
            } else {
                $selectAll.prop('checked', false);
            }

            if (session.count === 0) {
                $selectAllCheckbox.removeClass('checkbox--indeterminate');
            } else {
                $selectAllCheckbox.addClass('checkbox--indeterminate');
            }
        },

        toggleCountUI = function ($ui, count) {
            var $parent = $ui.parent();

            if (count > 0) {
                $parent.removeClass('hidden');
            } else if (count <= 0) {
                $parent.addClass('hidden');
            }
        },

        setCount = function (scope, count) {
            var $ui = $('[data-bulk-action-item-count]', scope);

            if (_.isEmpty($ui)) {
                var $placeholder = $('[data-bulk-action-count-placeholder]', scope),
                    $countUI = $(countUI({ count: count }));

                if (count <= 0) {
                    $countUI.addClass('hidden');
                }

                $placeholder.replaceWith($countUI);
            } else {
                $ui.text(count);
            }

            toggleCountUI($ui, count);
        },

        reset = function ($scope) {
            var $selectAll, $itemInputs, $count, $forms;

            $scope = ($scope instanceof jQuery) ? $scope : $(document);
            $selectAll = $('[data-bulk-action-select-all]', $scope),
            $itemInputs = $('[data-bulk-action-item]', $scope);
            $count = $('[data-bulk-action-item-count]', $scope);
            $forms = $('[data-bulk-action-form]', $scope);

            $selectAll.prop('checked', false);
            $itemInputs.prop('checked', false);

            $count.text($count.data('bulkActionItemCount'));

            $('input', $forms).filter(function(index, input) {
                return $(input).data('addedByBulkActionItem');
            }).remove();
        },

        destroy = _.flow(reset, removeSession),

        recall = function ($scope) {
            var session = getSession(),
                $selectAll = $('[data-bulk-action-select-all]', $scope),
                $itemInputs = $('[data-bulk-action-item]', $scope),

                selectedItems = function (index, item) {
                    return _.includes(session.ids, item.value);
                },

                itemsNotExcluded = function (index, item) {
                    return ! _.includes(session.excludeIds, item.value);
                };

            if (session.includeAll) {
                $selectAll.prop('checked', true);

                if (_.isEmpty(session.excludeIds)) {
                    $itemInputs.prop('checked', true);
                } else {
                    $itemInputs.filter(itemsNotExcluded).prop('checked', true);
                }
            } else {
                if ( ! _.isEmpty(session.ids)) {
                    $itemInputs.filter(selectedItems).prop('checked', true);
                }
            }

            setCount($scope, session.count);
        },


        //
        // Bootstrap
        removeAll = function (event, session) {
            var $itemInputs =
                    $(event.target)
                        .closest('table')
                            .find('[data-bulk-action-item]');

            $itemInputs.prop('checked', false);

            session.ids = [];
            session.excludeIds = [];
            session.includeAll = false;
            session.count = 0;

            return session;
        },

        addAll = function (event, session) {
            var $itemInputs =
                    $(event.target)
                        .closest('table')
                            .find('[data-bulk-action-item]');

            $itemInputs.prop('checked', true);

            session.ids = [];
            session.excludeIds = [];
            session.includeAll = true;
            session.count = session.initialCount;

            return session;
        },

        remove = function (event, session) {
            if (session.includeAll) {
                session.excludeIds.push(event.target.value);
            } else {
                _.remove(session.ids, function (id) {
                    return id === event.target.value;
                });
            }

            session.count -= 1;

            return session;
        },

        add = function (event, session) {
            if (session.includeAll) {
                _.remove(session.excludeIds, function (id) {
                    return id === event.target.value;
                });
            } else {
                session.ids.push(event.target.value);
            }

            session.count += 1;

            return session;
        },


        //
        // Event Handlers
        handleButtons = function (event) {
            var session = getSession(), idInputs, excludeIdsInputs;

            if (_.isNull(session)) { return; }

            idInputs = buildInputGroup(session.ids, 'ids'),
            excludeIdsInputs = buildInputGroup(session.excludeIds, 'exclude_ids');

            _.each(idInputs.concat(excludeIdsInputs), function($input) {
                $input.appendTo(event.target);
            });

            removeSession();
        },

        handleSelectAll = function (event) {
            var session = getSession() || setup(),
                $selectAll = $(event.target).parent('.checkbox'),
                wasChecked = event.target.checked,
                someSelected = $selectAll.is('.checkbox--indeterminate'),
                allSelected = session.count === session.initialCount,
                shouldSelectAll;

            event.preventDefault();

            if (wasChecked) {
                if (someSelected || allSelected) {
                    shouldSelectAll = false;
                } else {
                    shouldSelectAll = true;
                }
            } else {
                shouldSelectAll = false;
            }

            if (shouldSelectAll) {
                session = addAll(event, session);
                $(event.target).prop('checked', true);
            } else {
                session = removeAll(event, session);
                $(event.target).prop('checked', false);
            }

            setSession(session);
            toggleSelectAll(event.delegateTarget, session);
            setCount(event.delegateTarget, session.count);
        },

        handleItems = function (event) {
            var session = getSession() || setup();

            if (event.target.checked) {
                session = add(event, session);
            } else {
                session = remove(event, session);
            }

            setSession(session);
            toggleSelectAll(event.delegateTarget, session);
            setCount(event.delegateTarget, session.count);
        },

        /**
         * @method
         * @name init
         * @memberof WORKAREA.bulkActionItems
         */
        init = function ($scope) {
            $scope
            .on('change', '[data-bulk-action-item]', handleItems)
            .on('change', '[data-bulk-action-select-all]', handleSelectAll)
            .on('submit', '[data-bulk-action-form]', handleButtons)
                .find('.browsing-controls')
                .on('click', 'a', removeSession)
                .on('submit', 'form', removeSession);

            sessionApplicable() ? recall($scope) : destroy($scope);
        };

    $(document).on('turbolinks:before-cache', reset);

    return {
        init: init,
        getSession: getSession
    };
}()));