/* global
    Discussion, DiscussionThreadShowView, DiscussionViewSpecHelper, DiscussionSpecHelper, DiscussionThreadView,
    DiscussionUtil, Thread, DiscussionContentView, ThreadResponseShowView
*/
(function() {
    'use strict';
    describe('DiscussionThreadView', function() {
        var assertContentVisible, assertExpandedContentVisible, assertResponseCountAndPaginationCorrect,
            createAjaxResponseJson, createTestResponseJson, postResponse, renderWithContent, renderWithTestResponses;
        beforeEach(function() {
            var deferred;
            DiscussionSpecHelper.setUpGlobals();
            DiscussionSpecHelper.setUnderscoreFixtures();
            jasmine.clock().install();
            this.threadData = DiscussionViewSpecHelper.makeThreadWithProps({});
            this.thread = new Thread(this.threadData);
            this.discussion = new Discussion(this.thread);
            deferred = $.Deferred();
            spyOn($, 'ajax').and.returnValue(deferred);
            spyOn(DiscussionThreadShowView.prototype, 'convertMath');
            spyOn(DiscussionContentView.prototype, 'makeWmdEditor');
            spyOn(DiscussionUtil, 'makeWmdEditor');
            spyOn(DiscussionUtil, 'setWmdContent');
            return spyOn(ThreadResponseShowView.prototype, 'convertMath');
        });
        afterEach(function() {
            $.ajax.calls.reset();
            return jasmine.clock().uninstall();
        });
        renderWithContent = function(view, content) {
            $.ajax.and.callFake(function(params) {
                params.success(createAjaxResponseJson(content, false), 'success');
                return {
                    always: function() {
                    }
                };
            });
            view.render();
            return jasmine.clock().tick(100);
        };
        renderWithTestResponses = function(view, count, options) {
            var index;
            return renderWithContent(view, _.extend({
                resp_total: count,
                children: count > 0 ? (function() {
                    var _i, _results;
                    _results = [];
                    for (index = _i = 1; 1 <= count ? _i <= count : _i >= count; index = 1 <= count ? ++_i : --_i) {
                        _results.push(createTestResponseJson(index));
                    }
                    return _results;
                })() : []
            }, options));
        };
        createTestResponseJson = function(index) {
            return {
                user_id: window.user.id,
                body: 'Response ' + index,
                id: 'id_' + index,
                created_at: '2015-01-01T22:20:28Z'
            };
        };
        assertContentVisible = function(view, selector, visible) {
            var content;
            content = view.$el.find(selector);
            expect(content.length).toBeGreaterThan(0);
            return content.each(function(i, elem) {
                return expect($(elem).is(':visible')).toEqual(visible);
            });
        };
        assertExpandedContentVisible = function(view, expanded) {
            expect(view.$el.hasClass('expanded')).toEqual(expanded);
            assertContentVisible(view, '.post-extended-content', expanded);
            assertContentVisible(view, '.forum-thread-expand', !expanded);
            return assertContentVisible(view, '.forum-thread-collapse', expanded);
        };
        assertResponseCountAndPaginationCorrect = function(view, countText, displayCountText, buttonText) {
            expect(view.$el.find('.response-count').text()).toEqual(countText);
            if (displayCountText) {
                expect(view.$el.find('.response-display-count').text()).toEqual(displayCountText);
            } else {
                expect(view.$el.find('.response-display-count').length).toEqual(0);
            }
            if (buttonText) {
                return expect(view.$el.find('.load-response-button').text()).toEqual(buttonText);
            } else {
                return expect(view.$el.find('.load-response-button').length).toEqual(0);
            }
        };
        createAjaxResponseJson = function(content, can_act) {
            return {
                content: content,
                annotated_content_info: {
                    ability: {
                        editable: can_act,
                        can_delete: can_act,
                        can_reply: can_act,
                        can_vote: can_act
                    }
                }
            };
        };
        postResponse = function(view, index) {
            var responseText, testResponseJson;
            testResponseJson = createTestResponseJson(index);
            responseText = testResponseJson.body;
            spyOn(view, 'getWmdContent').and.returnValue(responseText);
            $.ajax.and.callFake(function(params) {
                expect(params.type).toEqual('POST');
                expect(params.data.body).toEqual(responseText);
                params.success(createAjaxResponseJson(testResponseJson, true), 'success');
                return {
                    always: function() {
                    }
                };
            });
            return view.$('.discussion-submit-post').click();
        };
        describe('closed and open Threads', function() {
            var checkCommentForm, checkVoteDisplay, createDiscussionThreadView;
            createDiscussionThreadView = function(originallyClosed, mode) {
                var discussion, thread, threadData, view;
                threadData = DiscussionViewSpecHelper.makeThreadWithProps({
                    closed: originallyClosed
                });
                thread = new Thread(threadData);
                discussion = new Discussion(thread);
                view = new DiscussionThreadView({
                    model: thread,
                    el: $('#fixture-element'),
                    mode: mode,
                    course_settings: DiscussionSpecHelper.createTestCourseSettings()
                });
                renderWithTestResponses(view, 1);
                if (mode === 'inline') {
                    view.expand();
                }
                spyOn(DiscussionUtil, 'updateWithUndo').and.callFake(function(model, updates) {
                    return model.set(updates);
                });
                return view;
            };
            checkCommentForm = function(originallyClosed, mode) {
                var view;
                view = createDiscussionThreadView(originallyClosed, mode);
                expect(view.$('.comment-form').closest('li').is(':visible')).toBe(!originallyClosed);
                expect(view.$('.discussion-reply-new').is(':visible')).toBe(!originallyClosed);
                view.$('.action-close').click();
                expect(view.$('.comment-form').closest('li').is(':visible')).toBe(originallyClosed);
                return expect(view.$('.discussion-reply-new').is(':visible')).toBe(originallyClosed);
            };
            checkVoteDisplay = function(originallyClosed, mode) {
                var view;
                view = createDiscussionThreadView(originallyClosed, mode);
                expect(view.$('.thread-main-wrapper .action-vote').is(':visible')).toBe(!originallyClosed);
                expect(view.$('.thread-main-wrapper .display-vote').is(':visible')).toBe(originallyClosed);
                view.$('.action-close').click();
                expect(view.$('.action-vote').is(':visible')).toBe(originallyClosed);
                return expect(view.$('.display-vote').is(':visible')).toBe(!originallyClosed);
            };
            return _.each(['tab', 'inline'], function(mode) {
                it(
                    'Test that in ' + mode + ' mode when a closed thread is opened the comment form is displayed',
                    function() { return checkCommentForm(true, mode); }
                );
                it(
                    'Test that in ' + mode + ' mode when a open thread is closed the comment form is hidden',
                    function() { return checkCommentForm(false, mode); }
                );
                it(
                    'Test that in ' + mode + ' mode when a closed thread is opened the vote button is displayed and ' +
                    'vote count is hidden',
                    function() { return checkVoteDisplay(true, mode); }
                );
                it(
                    'Test that in ' + mode + ' mode when a open thread is closed the vote button is hidden and ' +
                    'vote count is displayed',
                    function() { return checkVoteDisplay(false, mode); }
                );
            });
        });
        describe('tab mode', function() {
            beforeEach(function() {
                this.view = new DiscussionThreadView({
                    model: this.thread,
                    el: $('#fixture-element'),
                    mode: 'tab',
                    course_settings: DiscussionSpecHelper.createTestCourseSettings()
                });
            });
            describe('responses', function() {
                it('can post a first response', function() {
                    renderWithTestResponses(this.view, 0);
                    postResponse(this.view, 1);
                    expect(this.view.$('.forum-response').length).toBe(1);
                    expect(this.view.$('.post-actions-list').find('.action-edit').parent('.is-hidden').length).toBe(1);
                    return expect(this.view.$('.response-actions-list').find('.action-edit')
                        .parent().not('.is-hidden').length).toBe(1);
                });
                it('can post a second response', function() {
                    renderWithTestResponses(this.view, 1);
                    expect(this.view.$('.forum-response').length).toBe(1);
                    expect(this.view.$('.post-actions-list').find('.action-edit').parent('.is-hidden').length).toBe(1);
                    expect(this.view.$('.response-actions-list').find('.action-edit').parent()
                        .not('.is-hidden').length).toBe(1);
                    postResponse(this.view, 2);
                    expect(this.view.$('.forum-response').length).toBe(2);
                    expect(this.view.$('.post-actions-list').find('.action-edit').parent('.is-hidden').length).toBe(1);
                    return expect(this.view.$('.response-actions-list').find('.action-edit').parent()
                        .not('.is-hidden').length).toBe(2);
                });
            });
            describe('response count and pagination', function() {
                it('correctly render for a thread with no responses', function() {
                    renderWithTestResponses(this.view, 0);
                    return assertResponseCountAndPaginationCorrect(this.view, '0 responses', null, null);
                });
                it('correctly render for a thread with one response', function() {
                    renderWithTestResponses(this.view, 1);
                    return assertResponseCountAndPaginationCorrect(
                        this.view, '1 response', 'Showing all responses', null
                    );
                });
                it('correctly render for a thread with one additional page', function() {
                    renderWithTestResponses(this.view, 1, {
                        resp_total: 2
                    });
                    return assertResponseCountAndPaginationCorrect(
                        this.view, '2 responses', 'Showing first response', 'Load all responses'
                    );
                });
                it('correctly render for a thread with multiple additional pages', function() {
                    renderWithTestResponses(this.view, 2, {
                        resp_total: 111
                    });
                    return assertResponseCountAndPaginationCorrect(
                        this.view, '111 responses', 'Showing first 2 responses', 'Load next 100 responses'
                    );
                });
                describe('on clicking the load more button', function() {
                    beforeEach(function() {
                        renderWithTestResponses(this.view, 1, {
                            resp_total: 5
                        });
                        return assertResponseCountAndPaginationCorrect(
                            this.view, '5 responses', 'Showing first response', 'Load all responses'
                        );
                    });
                    it('correctly re-render when all threads have loaded', function() {
                        renderWithTestResponses(this.view, 5, {
                            resp_total: 5
                        });
                        this.view.$el.find('.load-response-button').click();
                        return assertResponseCountAndPaginationCorrect(
                            this.view, '5 responses', 'Showing all responses', null
                        );
                    });
                    it('correctly re-render when one page remains', function() {
                        renderWithTestResponses(this.view, 3, {
                            resp_total: 42
                        });
                        this.view.$el.find('.load-response-button').click();
                        return assertResponseCountAndPaginationCorrect(
                            this.view, '42 responses', 'Showing first 3 responses', 'Load all responses'
                        );
                    });
                    it('correctly re-render when multiple pages remain', function() {
                        renderWithTestResponses(this.view, 3, {
                            resp_total: 111
                        });
                        this.view.$el.find('.load-response-button').click();
                        return assertResponseCountAndPaginationCorrect(
                            this.view, '111 responses', 'Showing first 3 responses', 'Load next 100 responses'
                        );
                    });
                });
            });
        });
        describe('inline mode', function() {
            beforeEach(function() {
                this.view = new DiscussionThreadView({
                    model: this.thread,
                    el: $('#fixture-element'),
                    mode: 'inline',
                    course_settings: DiscussionSpecHelper.createTestCourseSettings()
                });
            });
            describe('render', function() {
                it('shows content that should be visible when collapsed', function() {
                    this.view.render();
                    return assertExpandedContentVisible(this.view, false);
                });
                it('does not render any responses by default', function() {
                    this.view.render();
                    expect($.ajax).not.toHaveBeenCalled();
                    return expect(this.view.$el.find('.responses li').length).toEqual(0);
                });
            });
            describe('focus', function() {
                it('sends focus to the conversation when opened', function(done) {
                    var self;
                    DiscussionViewSpecHelper.setNextResponseContent({
                        resp_total: 0,
                        children: []
                    });
                    this.view.render();
                    this.view.expand();
                    self = this;
                    return jasmine.waitUntil(function() {
                        var article;
                        article = self.view.$el.find('.discussion-article');
                        return article[0] === article[0].ownerDocument.activeElement;
                    }).then(function() {
                        return done();
                    });
                });
            });
            describe('expand/collapse', function() {
                it('shows/hides appropriate content', function() {
                    DiscussionViewSpecHelper.setNextResponseContent({
                        resp_total: 0,
                        children: []
                    });
                    this.view.render();
                    this.view.expand();
                    assertExpandedContentVisible(this.view, true);
                    this.view.collapse();
                    return assertExpandedContentVisible(this.view, false);
                });
                it('switches between the abbreviated and full body', function() {
                    var expectedAbbreviation, longBody;
                    DiscussionViewSpecHelper.setNextResponseContent({
                        resp_total: 0,
                        children: []
                    });
                    longBody = new Array(100).join('test ');
                    expectedAbbreviation = DiscussionUtil.abbreviateString(longBody, 140);
                    this.thread.set('body', longBody);
                    this.view.render();
                    expect($('.post-body').text()).toEqual(expectedAbbreviation);
                    expect(DiscussionThreadShowView.prototype.convertMath).toHaveBeenCalled();
                    DiscussionThreadShowView.prototype.convertMath.calls.reset();
                    this.view.expand();
                    expect($('.post-body').text()).toEqual(longBody);
                    expect(DiscussionThreadShowView.prototype.convertMath).toHaveBeenCalled();
                    DiscussionThreadShowView.prototype.convertMath.calls.reset();
                    this.view.collapse();
                    expect($('.post-body').text()).toEqual(expectedAbbreviation);
                    return expect(DiscussionThreadShowView.prototype.convertMath).toHaveBeenCalled();
                });
                it('strips script tags appropriately', function() {
                    var longMaliciousBody, maliciousAbbreviation;
                    DiscussionViewSpecHelper.setNextResponseContent({
                        resp_total: 0,
                        children: []
                    });
                    longMaliciousBody = new Array(100).join(
                        "<script>alert('Until they think warm days will never cease');</script>\n"
                    );
                    this.thread.set('body', longMaliciousBody);
                    maliciousAbbreviation = DiscussionUtil.abbreviateString(this.thread.get('body'), 140);
                    this.view.render();
                    expect($('.post-body').html()).not.toEqual(maliciousAbbreviation);
                    expect($('.post-body').text()).toEqual(maliciousAbbreviation);
                    expect($('.post-body').html()).not.toContain('<script');
                    this.view.expand();
                    expect($('.post-body').html()).not.toEqual(longMaliciousBody);
                    expect($('.post-body').text()).toEqual(longMaliciousBody);
                    expect($('.post-body').html()).not.toContain('<script');
                    this.view.collapse();
                    expect($('.post-body').html()).not.toEqual(maliciousAbbreviation);
                    expect($('.post-body').text()).toEqual(maliciousAbbreviation);
                    return expect($('.post-body').html()).not.toContain('<script');
                });
                it('re-renders the show view correctly when leaving the edit view', function() {
                    DiscussionViewSpecHelper.setNextResponseContent({
                        resp_total: 0,
                        children: []
                    });
                    this.view.render();
                    this.view.expand();
                    assertExpandedContentVisible(this.view, true);
                    this.view.edit();
                    assertContentVisible(this.view, '.edit-post-body', true);
                    expect(this.view.$el.find('.post-actions-list').length).toBe(0);
                    this.view.closeEditView(DiscussionSpecHelper.makeEventSpy());
                    expect(this.view.$el.find('.edit-post-body').length).toBe(0);
                    return assertContentVisible(this.view, '.post-actions-list', true);
                });
            });
        });
        describe('for question threads', function() {
            var generateContent, renderTestCase;
            beforeEach(function() {
                this.thread.set('thread_type', 'question');
                this.view = new DiscussionThreadView({
                    model: this.thread,
                    el: $('#fixture-element'),
                    mode: 'tab',
                    course_settings: DiscussionSpecHelper.createTestCourseSettings()
                });
            });
            generateContent = function(idStart, idEnd) {
                return _.map(_.range(idStart, idEnd), function(i) {
                    return createTestResponseJson(i);
                });
            };
            renderTestCase = function(view, numEndorsed, numNonEndorsed) {
                renderWithContent(view, {
                    endorsed_responses: generateContent(0, numEndorsed),
                    non_endorsed_responses: generateContent(numEndorsed, numEndorsed + numNonEndorsed),
                    non_endorsed_resp_total: numNonEndorsed
                });
                expect(view.$('.js-marked-answer-list .discussion-response').length).toEqual(numEndorsed);
                expect(view.$('.js-response-list .discussion-response').length).toEqual(numNonEndorsed);
                return assertResponseCountAndPaginationCorrect(
                    view, '' + numNonEndorsed + ' ' + (numEndorsed ? 'other ' : '') +
                    (numNonEndorsed === 1 ? 'response' : 'responses'),
                    numNonEndorsed ? 'Showing all responses' : null, null
                );
            };
            _.each({
                'no': 0,
                'one': 1,
                'many': 5
            }, function(numEndorsed, endorsedDesc) {
                return _.each({
                    'no': 0,
                    'one': 1,
                    'many': 5
                }, function(numNonEndorsed, nonEndorsedDesc) {
                    it(
                        'renders correctly with ' + endorsedDesc + ' marked answer(s) and ' + nonEndorsedDesc +
                        ' response(s)',
                        function() { return renderTestCase(this.view, numEndorsed, numNonEndorsed); }
                    );
                });
            });
            it('handles pagination correctly', function() {
                renderWithContent(this.view, {
                    endorsed_responses: generateContent(0, 2),
                    non_endorsed_responses: generateContent(3, 6),
                    non_endorsed_resp_total: 42
                });
                DiscussionViewSpecHelper.setNextResponseContent({
                    endorsed_responses: generateContent(0, 3),
                    non_endorsed_responses: generateContent(6, 9),
                    non_endorsed_resp_total: 41
                });
                this.view.$el.find('.load-response-button').click();
                expect($('.js-marked-answer-list .discussion-response').length).toEqual(3);
                expect($('.js-response-list .discussion-response').length).toEqual(6);
                return assertResponseCountAndPaginationCorrect(
                    this.view, '41 other responses', 'Showing first 6 responses', 'Load all responses'
                );
            });
        });
        describe('post restrictions', function() {
            beforeEach(function() {
                this.thread.attributes.ability = _.extend(this.thread.attributes.ability, {
                    can_report: false,
                    can_vote: false
                });
                this.view = new DiscussionThreadView({
                    model: this.thread,
                    el: $('#fixture-element'),
                    mode: 'tab',
                    course_settings: DiscussionSpecHelper.createTestCourseSettings()
                });
            });
            it("doesn't show report option if can_report ability is disabled", function() {
                this.view.render();
                return expect(this.view.$el.find('.action-report').closest('.actions-item')).toHaveClass('is-hidden');
            });
            it("doesn't show voting button if can_vote ability is disabled", function() {
                this.view.render();
                return expect(this.view.$el.find('.action-vote').closest('.actions-item')).toHaveClass('is-disabled');
            });
        });
    });
}).call(this);
