define([
    'jquery',
    'Squire',
    'test-helper'
], function (
    $,
    Squire,
    testHelper
) {

    'use strict';

    QUnit.module('timezone-onboarding-test', {
        beforeEach: function() {
            var localOffset = new Date().getTimezoneOffset();
            $('#qunit-fixture').append($('<div id="content" data-timezone="' + localOffset + '"></div>'));
        }
    });

    var injector = new Squire();
    injector.setDefaultDeps(['bitbucket/internal/feature/timezone/onboarding']);
    testHelper.setTemplates({
        'bitbucket.internal.feature.timezone.onboarding.flagBody':
            '<div><button id="time-zone-onboarding-change"></button><button id="time-zone-onboarding-dismiss"></button></div>'
    });

    var OFFSETS = {
        LOCAL: new Date().getTimezoneOffset(),
        NOT_LOCAL: new Date().getTimezoneOffset() + 1,
        ELSEWHERE: new Date().getTimezoneOffset() + 2
    };
    var flagSpy = {
        close: sinon.spy()
    };
    var mocks = {
        'aui': {
            contextPath: function() {
                return '';
            },
            I18n: {
                getText: sinon.spy()
            }
        },
        'aui/flag': sinon.spy(function(options) {
            $('#qunit-fixture').append(options.body);
            return flagSpy;
        }),
        'bitbucket/internal/model/page-state': testHelper.mockPageState(),
        'bitbucket/internal/util/ajax': {
            rest: sinon.stub().returns($.Deferred().resolve({
                'USER_BROWSER_TIME_ZONE_OFFSET': OFFSETS.ELSEWHERE
            }).promise())
        },
        'bitbucket/internal/util/client-storage': {
            getItem: sinon.stub().withArgs('bitbucket_known_time_zone_offset').returns(OFFSETS.NOT_LOCAL),
            setItem: sinon.spy()
        },
        'bitbucket/internal/util/events': {
            trigger: sinon.spy()
        },
        'bitbucket/internal/util/feature-enabled': {
            getFromProvider: function () {
                return $.Deferred().resolve(true).promise();
            }
        }
    };

    Object.keys(mocks).forEach(function(module) {
        injector.mock(module, mocks[module]);
    });

    injector.test('No action for anonymous user', function(assert, onboarding) {
        $('#content').attr('data-timezone', OFFSETS.NOT_LOCAL);
        assert.expect(2);
        var done = assert.async();
        var getUser = sinon.stub(mocks['bitbucket/internal/model/page-state'], 'getCurrentUser', function () {
            return undefined;
        });

        onboarding.onReady().fail(function () {
            assert.ok(true, 'Promise rejected');
            done();
        });
        assert.ok(getUser.called);

        mocks['bitbucket/internal/model/page-state'].getCurrentUser.restore();
    });

    injector.test('Known offset changed local result verified', function(assert, onboarding) {
        $('#content').attr('data-timezone', OFFSETS.NOT_LOCAL);
        var getItem = mocks['bitbucket/internal/util/client-storage'].getItem;
        mocks['bitbucket/internal/util/client-storage'].getItem = sinon.stub()
            .withArgs('bitbucket_known_time_zone_offset').returns(null);

        onboarding.onReady();

        assertTriedToGetItemFromLocalStorage();
        assertTriedToGetItemFromServer();

        assert.ok($('#time-zone-onboarding-dismiss').length, 'Flag shown');

        mocks['bitbucket/internal/util/client-storage'].getItem = getItem;
    });

    injector.test('Dismiss button closes flag', function(assert, onboarding) {
        $('#content').attr('data-timezone', OFFSETS.NOT_LOCAL);

        onboarding.onReady();

        assertEventTriggered('bitbucket.internal.ui.time.zone.onboarding.shown');
        assert.ok(mocks['aui/flag'].called);

        var $dismiss = $('#time-zone-onboarding-dismiss');
        assert.ok($dismiss.length === 1);

        $dismiss.click();
        assertEventTriggered('bitbucket.internal.ui.time.zone.onboarding.dismissed');
        assertSetKnownBrowserOffsetCalled();
        assert.ok(flagSpy.close.called);
    });

    injector.test('Change tz button navigates', function(assert, onboarding) {
        $('#content').attr('data-timezone', OFFSETS.NOT_LOCAL);
        var navigate = sinon.stub(onboarding, "navigate");

        onboarding.onReady();

        assertEventTriggered('bitbucket.internal.ui.time.zone.onboarding.shown');
        assert.ok(mocks['aui/flag'].called);

        var $change = $('#time-zone-onboarding-change');
        assert.ok($change.length === 1);

        $change.click();

        assertEventTriggered('bitbucket.internal.ui.time.zone.onboarding.changed');
        assertSetKnownBrowserOffsetCalled();
        sinon.assert.calledOnce(flagSpy.close);
        sinon.assert.calledWith(navigate, '/account');

        onboarding.navigate.restore();
    });

    injector.test('Server Known TZ is saved to LS', function(assert, onboarding) {
        $('#content').attr('data-timezone', OFFSETS.NOT_LOCAL);

        var rest = mocks['bitbucket/internal/util/ajax'].rest;

        mocks['bitbucket/internal/util/ajax'].rest = sinon.stub().returns($.Deferred().resolve({
            'USER_BROWSER_TIME_ZONE_OFFSET': OFFSETS.LOCAL
        }).promise())

        onboarding.onReady();

        assertLocalStorageSet();
        assert.ok(mocks['bitbucket/internal/util/ajax'].rest.calledOnce);

        mocks['bitbucket/internal/util/ajax'].rest = rest;
    });

    function assertEventTriggered(name) {
        sinon.assert.calledWith(mocks['bitbucket/internal/util/events'].trigger, name);
    }

    function assertTriedToGetItemFromLocalStorage() {
        sinon.assert.calledWith(mocks['bitbucket/internal/util/client-storage'].getItem, 'bitbucket_known_time_zone_offset');
    }

    function assertTriedToGetItemFromServer() {
        sinon.assert.calledWithMatch(mocks['bitbucket/internal/util/ajax'].rest, {
            url: '/rest/api/latest/users/username/settings',
            type: 'GET'
        });
    }

    function assertLocalStorageSet() {
        sinon.assert.calledWith(mocks['bitbucket/internal/util/client-storage'].setItem, 'bitbucket_known_time_zone_offset', String(OFFSETS.LOCAL));
    }

    function assertSetKnownBrowserOffsetCalled() {
        sinon.assert.calledWithMatch(mocks['bitbucket/internal/util/ajax'].rest, {
            url: '/rest/api/latest/users/username/settings',
            type: 'POST'
        });
        assertLocalStorageSet();
    }
});