describe "DownloadJamTrack", ->

  beforeEach ->
    this.fixtures = fixture.load("downloadJamTrack.html"); # append these fixtures which were already cached
    window.jamClient = sinon.stub()
    this.app = sinon.stub()
    this.jamTrackId = '1'
    this.jamTrack = {id: this.jamTrackId, jam_track_right_id: '1', name: 'Back in Black', version:'1'}
    window.gon = {}
    window.JK.JamServer = {}
    window.stats = {}
    @statsSpy = window.stats.write = sinon.spy()
    window.JK.JamServer.send = sinon.stub(); # attempts to subscribe to the socket will need this

  afterEach ->
    window.stats.write.reset()

  describe "normal browser", ->

    beforeEach ->
      window.gon.isNativeClient = false
      @showNoClientSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showNoClient')
      @downloadJamTrack = new JK.DownloadJamTrack(@app, @jamTrack)
      $('body').append(this.downloadJamTrack.root)

    afterEach ->
      @showNoClientSpy.restore()

    it "switches to 'no client' correctly", ->
      window.jamClient.JamTrackGetTrackDetail = sinon.stub()
      window.jamClient.InvalidateJamTrack = sinon.stub()
      #window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'ready'})

      @downloadJamTrack.init();

      expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(0)
      expect(@showNoClientSpy.calledOnce).toBe(true)
      expect(@downloadJamTrack.stateHolder.find('.state-no-client')).toHaveLength(1)
      expect(@statsSpy.calledOnce).toBe(true)

  describe "client", ->

    beforeEach ->
      window.gon.isNativeClient = true

    describe "already synchronized", ->
      beforeEach ->
        @showSynchronizedSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showSynchronized')
        @downloadJamTrack = new JK.DownloadJamTrack(@app, @jamTrack)
        $('body').append(@downloadJamTrack.root)

      afterEach ->
        @showSynchronizedSpy.restore()
        @downloadJamTrack.destroy()

      it "shows synchronized state", ->
        window.jamClient.JamTrackGetTrackDetail = sinon.stub()
        window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'ready', 'version' : '1'})
        window.jamClient.InvalidateJamTrack = sinon.stub()

        @downloadJamTrack.init();

        expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(1)
        expect(window.jamClient.InvalidateJamTrack.callCount).toBe(0)
        expect(@showSynchronizedSpy.calledOnce).toBe(true)
        expect(@downloadJamTrack.transitionTimer).toBe(null)
        expect(@downloadJamTrack.downloadTimer).toBe(null)
        expect(@statsSpy.calledOnce).toBe(true)

        expect(@downloadJamTrack.stateHolder.find('.state-synchronized')).toHaveLength(1)

    describe "pending", ->
      beforeEach ->
        window.jamClient.JamTrackKeysRequest = sinon.stub()
        @showSynchronizedSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showSynchronized')
        @showErrorSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showError')
        @showKeyingSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showKeying')
        @downloadJamTrack = new JK.DownloadJamTrack(@app, @jamTrack)
        @downloadJamTrack.states.keying.max_time = -1 # hurry up the test, instead of waiting 10 seconds
        $('body').append(@downloadJamTrack.root)

      afterEach ->
        @showSynchronizedSpy.restore()
        @showErrorSpy.restore()
        @showKeyingSpy.restore()
        @downloadJamTrack.destroy()

      it "shows errored state due to timeout", ->
        window.jamClient.JamTrackGetTrackDetail = sinon.stub()
        window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'pending', 'version' : '1'})
        window.jamClient.InvalidateJamTrack = sinon.stub()

        @downloadJamTrack.init();

        expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(1)
        expect(@showKeyingSpy.calledOnce).toBe(true)
        expect(@downloadJamTrack.states.keying.timer).toNotBe(null)

        @downloadJamTrack.stateIntervalCheck()

        expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(2)

        expect(@showErrorSpy.calledOnce).toBe(true)
        expect(@downloadJamTrack.states.keying.timer).toBe(null)
        expect(@downloadJamTrack.stateHolder.find('.state-errored')).toHaveLength(1)
        expect(@downloadJamTrack.stateHolder.find('.state-errored .msg')).toContainText('It took too long for the JamTrack to be keyed.')
        expect(@statsSpy.calledOnce).toBe(true)
        expect(@downloadJamTrack.attempts).toBe(1)

        # now simulate a retry attempt
        @downloadJamTrack.stateHolder.find('.retry-button').trigger('click')

        # and verify that we are beginning a re-attempt
        expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(3)
        expect(@showKeyingSpy.calledTwice).toBe(true)
        expect(@downloadJamTrack.states.keying.timer).toNotBe(null)
        expect(@downloadJamTrack.attempts).toBe(2)


      it "shows synchronized", ->
        window.jamClient.JamTrackGetTrackDetail = sinon.stub()
        window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'pending', 'version' : '1'})
        window.jamClient.InvalidateJamTrack = sinon.stub()

        @downloadJamTrack.init()

        expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(1)
        expect(@showKeyingSpy.calledOnce).toBe(true)

        # keying timer should be firing
        expect(@downloadJamTrack.states.keying.timer).toNotBe(null)

        # say the keys have been fetched
        window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'ready', 'version' : '1'})
        window.jamClient.InvalidateJamTrack = sinon.stub()

        # then do a check
        @downloadJamTrack.stateIntervalCheck()

        expect(@showSynchronizedSpy.calledOnce).toBe(true)
        expect(@downloadJamTrack.states.keying.timer).toBe(null)
        expect(@downloadJamTrack.stateHolder.find('.state-synchronized')).toHaveLength(1)
        expect(@statsSpy.calledOnce).toBe(true)



    describe "JamTrack needs downloading", ->
      beforeEach ->
        window.jamClient.JamTrackDownload = sinon.stub()
        @showSynchronizedSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showSynchronized')
        @showErrorSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showError')
        @showKeyingSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showKeying')
        @showDownloadingSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showDownloading')
        @showPackagingSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showPackaging')
        @downloadJamTrack = new JK.DownloadJamTrack(@app, @jamTrack)
        @downloadJamTrack.states.keying.max_time = -1 # hurry up the test, instead of waiting 10 seconds
        $('body').append(@downloadJamTrack.root)

      afterEach ->
        @showSynchronizedSpy.restore()
        @showErrorSpy.restore()
        @showKeyingSpy.restore()
        @showDownloadingSpy.restore()
        @showPackagingSpy.restore()
        @downloadJamTrack.destroy()

      it "shows downloading for signed package", ->
        window.jamClient.JamTrackKeysRequest = sinon.stub()
        window.jamClient.JamTrackGetTrackDetail = sinon.stub()
        window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'unknown', 'version' : '1'})
        window.jamClient.InvalidateJamTrack = sinon.stub()

        spyOn(@downloadJamTrack.rest, 'getJamTrackRight').andCallFake((data) =>
          d = $.Deferred();
          d.resolve({signing_state: 'SIGNED'});
          d.promise();
        )

        window.jamClient.JamTrackDownload = sinon.stub()

        @downloadJamTrack.init()

        expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(1)
        expect(window.jamClient.JamTrackDownload.callCount).toBe(1)
        expect(@showDownloadingSpy.calledOnce).toBe(true)
        expect(@downloadJamTrack.stateHolder.find('.state-downloading')).toHaveLength(1)

        eval(@downloadJamTrack.makeDownloadSuccessCallback() + '()')

        expect(@showKeyingSpy.calledOnce).toBe(true)
        expect(@downloadJamTrack.stateHolder.find('.state-keying')).toHaveLength(1)

        # keying timer should be firing
        expect(@downloadJamTrack.states.keying.timer).toNotBe(null)

        # say the keys have been fetched
        window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'ready', 'version' : '1'})
        window.jamClient.InvalidateJamTrack = sinon.stub()

        # check state again
        @downloadJamTrack.stateIntervalCheck()

        # we should now be synchronized
        expect(@showSynchronizedSpy.calledOnce).toBe(true)
        expect(@downloadJamTrack.states.keying.timer).toBe(null)
        expect(@downloadJamTrack.stateHolder.find('.state-synchronized')).toHaveLength(1)
        expect(@statsSpy.calledOnce).toBe(true)

      it "is not yet packaged", ->
        window.jamClient.JamTrackGetTrackDetail = sinon.stub()
        window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'unknown', 'version' : '1'})
        window.jamClient.InvalidateJamTrack = sinon.stub()

        spyOn(@downloadJamTrack.rest, 'getJamTrackRight').andCallFake((data) =>
          d = $.Deferred();
          d.resolve({signing_state: 'QUIET'});
          d.promise();
        )

        spyOn(@downloadJamTrack.rest, 'enqueueJamTrack').andCallFake((data) =>
          d = $.Deferred();
          d.resolve({});
          d.promise();
        )

        window.jamClient.JamTrackDownload = sinon.stub()

        @downloadJamTrack.init()

        expect(@downloadJamTrack.attemptedEnqueue).toBe(true)
        expect(@downloadJamTrack.transitionTimer?).toBe(true)

        # simulate poke from server saying the track has been queued
        @downloadJamTrack.onJamTrackRightEvent(null, {body: {signing_state: 'QUEUED'}})

        # the frontend should be saying that it's packaging now
        expect(@downloadJamTrack.transitionTimer?).toBe(true)
        expect(@showPackagingSpy.calledOnce).toBe(true)
        expect(@downloadJamTrack.stateHolder.find('.state-packaging')).toHaveLength(1)

        # simulate poke from server saying the track is currently signing
        @downloadJamTrack.onJamTrackRightEvent(null, {body: {signing_state: 'SIGNING'}})

        # the frontend still be saying it's packaging
        expect(@downloadJamTrack.transitionTimer?).toBe(true)
        expect(@showPackagingSpy.calledOnce).toBe(true)

        # simulate poke from server saying the track is signed
        @downloadJamTrack.onJamTrackRightEvent(null, {body: {signing_state: 'SIGNED'}})

        expect(@downloadJamTrack.transitionTimer?).toBe(false)

        # downloading has started; other test covers this, so we stop testing
        expect(@showDownloadingSpy.calledOnce).toBe(true)
        expect(@downloadJamTrack.stateHolder.find('.state-downloading')).toHaveLength(1)

        # since we haven't yet made it to a leave node, make sure we haven't reported a stat
        expect(@statsSpy.callCount).toBe(0)

      it "queue time out when packaging", ->
        window.jamClient.JamTrackGetTrackDetail = sinon.stub()
        window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'unknown', 'version' : '1'})
        window.jamClient.InvalidateJamTrack = sinon.stub()

        getJamTrackRightSpy = spyOn(@downloadJamTrack.rest, 'getJamTrackRight')
        getJamTrackRightSpy.andCallFake((data) =>
          d = $.Deferred();
          d.resolve({signing_state: 'QUIET'});
          d.promise();
        )

        spyOn(@downloadJamTrack.rest, 'enqueueJamTrack').andCallFake((data) =>
          d = $.Deferred();
          d.resolve({});
          d.promise();
        )

        window.jamClient.JamTrackDownload = sinon.stub()

        @downloadJamTrack.init()

        expect(@downloadJamTrack.attemptedEnqueue).toBe(true)
        expect(@downloadJamTrack.transitionTimer?).toBe(true)

        getJamTrackRightSpy.reset()

        # simulate timer running out, and server check resulting in QUEUED_TIMEOUT
        getJamTrackRightSpy.andCallFake((data) =>
          d = $.Deferred();
          d.resolve({signing_state: 'QUEUED_TIMEOUT'});
          d.promise();
        )

        @downloadJamTrack.transitionCheck()

        # the frontend should be saying that it's packaging now
        expect(@downloadJamTrack.transitionTimer?).toBe(false)
        expect(@showErrorSpy.calledOnce).toBe(true)
        expect(@downloadJamTrack.stateHolder.find('.state-errored')).toHaveLength(1)
        expect(@downloadJamTrack.stateHolder.find('.state-errored .msg')).toContainText('The server took too long to begin processing your JamTrack.')

        expect(@statsSpy.calledOnce).toBe(true)








