/* global AJS:false */
AJS.test.require("com.atlassian.bitbucket.server.bitbucket-web:time", function() {

    'use strict';

    // NOTE: Ensure all test logic matches DateFormatterTest
    var moment;
    var timeJS;
    var $;

    function assertRelativeUsesFormatStringForDate(now, date, type) {
        type = type || "timestamp";
        try {
            equal(
                timeJS.formatDateWithRelativeAge(date.clone(), timeJS.FormatType.types[type], now.clone()),
                timeJS.formatDateWithFormatString(date.clone(), timeJS.FormatType.types[type]),
                'Relative matches format string for ' + date.toDate().toUTCString());
        } catch(e) {
            ok(false, 'Error checking relative == format string with args ' + date.toDate().toUTCString() + ' and ' + type + '.\nCause: ' + e.toString());
        }
    }

    module('util-time', {
        setup : function() {
            moment = require('moment');
            timeJS = require('bitbucket/internal/util/time');
            $ = jQuery;
        },
        teardown : function() {
        }
    });

    function withTimezone(tz, fn) {
        sinon.stub(timeJS, "getTimezoneOffset", function () {
            return tz;
        });
        fn && fn();
        timeJS.getTimezoneOffset.restore();
    }

    test('format date with relative age', function() {

        function assertRelativeAge(now, date, expectedString) {
            equal(timeJS.formatDateWithRelativeAge(date.clone(), timeJS.FormatType.types.shortAge, now.clone()), expectedString, 'Formatted date is ' + expectedString);
        }

        // +03:00
        withTimezone(-3 * 60, function () {
            var midnight = moment(new Date("2012-02-16T00:00:00.000+03:00"));
            var now = midnight.clone().add('d', 1).subtract('ms', 1); // 11:59pm 16 Feb 2012

            assertRelativeAge(now, now, "A moment ago");
            assertRelativeAge(now, now.clone().subtract('s', 59), "A moment ago");

            assertRelativeAge(now, now.clone().subtract('s', 60).add('ms', 1), "A moment ago");
            assertRelativeAge(now, now.clone().subtract('s', 60), "1 min ago");
            assertRelativeAge(now, now.clone().subtract('s', 60).subtract('ms', 1), "1 min ago");

            assertRelativeAge(now, now.clone().subtract('m', 1).subtract('s', 29), "1 min ago");
            assertRelativeAge(now, now.clone().subtract('m', 1).subtract('s', 30), "1 min ago");
            assertRelativeAge(now, now.clone().subtract('m', 1).subtract('s', 31), "1 min ago");

            assertRelativeAge(now, now.clone().subtract('m', 2).add('s', 1), "1 min ago");
            assertRelativeAge(now, now.clone().subtract('m', 2), "2 mins ago");
            assertRelativeAge(now, now.clone().subtract('m', 2).subtract('s', 1), "2 mins ago");

            assertRelativeAge(now, now.clone().subtract('m', 2).subtract('s', 29), "2 mins ago");
            assertRelativeAge(now, now.clone().subtract('m', 2).subtract('s', 30), "2 mins ago");
            assertRelativeAge(now, now.clone().subtract('m', 2).subtract('s', 31), "2 mins ago");

            assertRelativeAge(now, now.clone().subtract('m', 29), "29 mins ago");
            assertRelativeAge(now, now.clone().subtract('m', 30), "30 mins ago");
            assertRelativeAge(now, now.clone().subtract('m', 31), "31 mins ago");

            assertRelativeAge(now, now.clone().subtract('m', 50).add('s', 1), "49 mins ago");
            assertRelativeAge(now, now.clone().subtract('m', 50), "1 hour ago");
            assertRelativeAge(now, now.clone().subtract('m', 50).subtract('s', 1), "1 hour ago");

            assertRelativeAge(now, now.clone().subtract('h', 1).subtract('m', 29), "1 hour ago");
            assertRelativeAge(now, now.clone().subtract('h', 1).subtract('m', 30), "2 hours ago");
            assertRelativeAge(now, now.clone().subtract('h', 1).subtract('m', 31), "2 hours ago");

            assertRelativeAge(now, now.clone().subtract('d', 1).add('ms', 1), "24 hours ago"); // Midnight
            assertRelativeAge(now, now.clone().subtract('d', 1), "Yesterday");

            assertRelativeAge(midnight, midnight.clone().subtract('h', 1), "1 hour ago");
            assertRelativeAge(midnight, midnight.clone().subtract('h', 5).add('s', 1), "5 hours ago");
            assertRelativeAge(midnight, midnight.clone().subtract('h', 5), "5 hours ago");

            assertRelativeAge(midnight, midnight.clone().subtract('h', 5).subtract('s', 1), "Yesterday");

            assertRelativeAge(midnight, midnight.clone().subtract('d', 1).add('ms', 1), "Yesterday");
            assertRelativeAge(midnight, midnight.clone().subtract('d', 1), "Yesterday");
            assertRelativeAge(midnight, midnight.clone().subtract('d', 1).subtract('ms', 1), "2 days ago");

            assertRelativeAge(now, now.clone().subtract('w', 1).add('ms', 1), "6 days ago");
            assertRelativeAge(now, now.clone().subtract('w', 1), "1 week ago");
            assertRelativeAge(now, now.clone().subtract('w', 1).subtract('ms', 1), "1 week ago");

            assertRelativeAge(now, now.clone().subtract('w', 1).add('ms', 1), "6 days ago");
            assertRelativeAge(now, now.clone().subtract('w', 1), "1 week ago");
            assertRelativeAge(now, now.clone().subtract('w', 1).subtract('d', 1).add('ms', 1), "1 week ago");

            //Future dates are explicit.
            assertRelativeUsesFormatStringForDate(now, now.clone().add('w', 1), 'shortAge');

            var str = timeJS.formatDateWithRelativeAge(now.clone().subtract('w', 1).subtract('d', 1), timeJS.FormatType.types.shortAge, now);
            ok(str);
        });
    });

    function assertFormatString(date, expected, type) {
        type = type || "timestamp";
        try {
            equal(timeJS.formatDateWithFormatString(date.clone(), timeJS.FormatType.types[type]), expected, 'formatted date is correct for ' + date.toDate().toUTCString());
        } catch(e) {
            ok(false, 'formatDateWithFormatString failed with args ' + date.toDate().toUTCString() + ' and ' + type + '.\nCause: ' + e.toString());
        }
    }

    test('format date with format string - format is correct (short, long, full, timestamp)', function() {
        // +03:00
        withTimezone(-3 * 60, function () {
            var midnight = moment(new Date("2012-02-16T00:00:00.000+03:00"));
            var now = midnight.clone().add('d', 1).subtract('ms', 1); // 11:59pm 16 Feb 2012 +03:00

            assertFormatString(now.clone(), "2012-02-16T23:59:59+0300", "timestamp");
            assertFormatString(now.clone(), "16 February 2012 11:59 PM", "full");
            assertFormatString(now.clone(), "16 February 2012",         "long");
            assertFormatString(now.clone(), "16 Feb 2012",              "short");
        });
    });

    test('format date with format string - timezone transform is correct', function() {

        var midnight = moment(new Date("2012-02-16T00:00:00.000+03:00"));
        var now = midnight.clone().add('d', 1).subtract('ms', 1); // 11:59pm 16 Feb 2012 +03:00

        // +03:00
        withTimezone(-3 * 60, function () {
            assertFormatString(now.clone(), "2012-02-16T23:59:59+0300");
        });

        // +00:00
        withTimezone(0, function () {
            assertFormatString(now.clone(), "2012-02-16T20:59:59+0000");
        });

        // +12:00
        withTimezone(-12 * 60, function () {
            assertFormatString(now.clone(), "2012-02-17T08:59:59+1200");
        });

        // -12:00
        withTimezone(12 * 60, function () {
            assertFormatString(now.clone(), "2012-02-16T08:59:59-1200");
        });

        // -00:30
        withTimezone(30, function () {
            assertFormatString(now.clone(), "2012-02-16T20:29:59-0030");
        });

        // TODO: DST tests - they will currently fail.  The browser will handle changes in TimeZoneOffset due to Daylight Saving,
        // TODO: but we're hardcoding an offset into the page for the current time.  This means if today is the first day of DST,
        // TODO: all our times for yesterday will be off by an hour.
    });
});