import * as luxon from 'luxon';

import * as ClockLib from 'src/lib/clock';

describe('src/lib/clock', () => {
  describe('Clock', () => {
    let fakeDateTime = null;

    beforeEach(() => {
      fakeDateTime = luxon.DateTime.local(1987, 10, 3, 8, 0, 1, 200);

      spyOn(window, 'setTimeout').and.returnValue(123);
      spyOn(window, 'clearTimeout');
      spyOn(luxon.DateTime, 'local').and.returnValue(fakeDateTime);
    });

    describe('constructor', () => {
      it('initializes an instance', () => {
        const clock = new ClockLib.Clock();

        expect(clock.now).toEqual(fakeDateTime);
        expect(clock.timeout).toBe(null);
      });
    });

    describe('clearTimeout', () => {
      it('is a noop is timeout is null', () => {
        const clock = new ClockLib.Clock();

        clock.clearTimeout();

        expect(window.clearTimeout).not.toHaveBeenCalled();
      });

      it('clears the timeout', () => {
        const clock = new ClockLib.Clock();
        clock.timeout = 123;

        clock.clearTimeout();

        expect(window.clearTimeout).toHaveBeenCalledWith(123);
        expect(clock.timeout).toBe(null);
      });
    });

    describe('onTimeout', () => {
      it('handles the clock timeout', () => {
        const newFakeDateTime = fakeDateTime.plus({minutes: 1});
        luxon.DateTime.local.and.returnValue(newFakeDateTime);

        const clock = new ClockLib.Clock();
        spyOn(clock, 'clearTimeout');
        spyOn(clock, 'fireEvent');
        spyOn(clock, 'start');

        clock.onTimeout();

        expect(clock.now).toEqual(newFakeDateTime);
        expect(clock.clearTimeout).toHaveBeenCalled();
        expect(clock.fireEvent).toHaveBeenCalledWith('tick');
        expect(clock.start).toHaveBeenCalled();
      });
    });

    describe('start', () => {
      it('starts the clock', () => {
        const clock = new ClockLib.Clock();

        clock.start();

        expect(window.setTimeout).toHaveBeenCalledWith(clock.onTimeout, 58810);
      });
    });

    describe('stop', () => {
      it('stops the clock', () => {
        const clock = new ClockLib.Clock();
        spyOn(clock, 'clearTimeout');

        clock.stop();

        expect(clock.clearTimeout).toHaveBeenCalled();
      });
    });
  });
});
