import { fromJS } from 'immutable'
import {
  CREATE_STIMULUS_CALL,
  UPDATE_STIMULUS_CALL
} from '@instructure/quiz-common/lib/constants'
import Fetcher from '../../../common/util/Fetcher'

import {
  startCallFor,
  successCallFor
} from '../../../common/util/callHelpers'

import Stimulus from '../../../common/records/Stimulus'

import {
  createStimulus,
  updateStimulus
} from '../stimuli'

import {
  addStimuli
} from '../../../common/actions/stimuli'

import makeFakeFetch from '../../../../tests/util/fakeFetch'
import { jsoniblePromise } from '../../../common/util/jsonify'

describe('stimulus api actions creators', () => {
  const dispatchStub = sinon.stub()
  const getStateStub = sinon.stub().returns(fromJS({ userSessions: {} }))
  const fetchStub = sinon.stub()

  useFakeFetching({dispatchStub, getStateStub, fetchStub})

  const stimulus = new Stimulus({
    id: '22',
    stimulusType: 'text',
    title: 'the title',
    instructions: 'the instructions',
    body: 'the body',
    sourceUrl: 'sourceUrl'
  })

  describe('createStimulus', () => {
    const stubbedCreateStimulusCall = () => {
      Fetcher.fakeFetch = fetchStub
      const createStimulusThunk = createStimulus(stimulus, '3', 'quiz')
      createStimulusThunk(dispatchStub, getStateStub)
    }

    it('should mark the create stimulus call as started', () => {
      const createCallAction = startCallFor(CREATE_STIMULUS_CALL)
      stubbedCreateStimulusCall()
      checkActionDispatched(dispatchStub, createCallAction)
    })

    it('should hit the right endpoint', () => {
      stubbedCreateStimulusCall()
      expect(fetchStub).to.be.calledWith('/api/quizzes/3/stimuli')
    })

    it('should serialize data properly', () => {
      stubbedCreateStimulusCall()
      const expectedData = JSON.stringify({
        stimulus: {
          body: 'the body',
          instructions: 'the instructions',
          parent_stimulus_id: null,
          source_url: 'sourceUrl',
          stimulus_type: 'text',
          title: 'the title'
        }
      })

      expect(
        fetchStub.getCall(0).args[1].body
      ).to.be.eql(expectedData)
    })

    const fakeCreateStimulus = () => {
      const response = jsoniblePromise(stimulus.toJS())
      const fakeFetch = makeFakeFetch(response)

      Fetcher.fakeFetch = fakeFetch
      const createStimulusThunk = createStimulus(stimulus)
      return createStimulusThunk(dispatchStub, getStateStub)
    }

    it('should mark the create call as a success on return', (done) => {
      const successfulCreate = successCallFor(CREATE_STIMULUS_CALL)
      const fetchPromise = fakeCreateStimulus()
      fetchPromise.then(() => {
        checkActionDispatched(dispatchStub, successfulCreate)
        done()
      })
    })

    it('should try to add the stimulus to the store', (done) => {
      const fetchPromise = fakeCreateStimulus()
      const handleStimulusAction = addStimuli([stimulus.toJS()])
      fetchPromise.then(() => {
        checkActionDispatched(dispatchStub, handleStimulusAction)
        done()
      })
    })
  })

  describe('updateStimulus', () => {
    const stimulusData = {
      id: '22',
      title: 'stimulus title',
      instructions: 'stimulus instructions',
      body: 'stimulus body',
      sourceUrl: 'stimulus sourceUrl'
    }
    const quizId = '3'

    const stubbedUpdateStimulusCall = () => {
      Fetcher.fakeFetch = fetchStub
      const stimulus = new Stimulus(stimulusData)
      const updateStimulusThunk = updateStimulus(stimulus, quizId)
      updateStimulusThunk(dispatchStub, getStateStub)
    }

    it('should hit the right endpoint', () => {
      stubbedUpdateStimulusCall()
      expect(fetchStub).to.be.calledWith('/api/quizzes/3/stimuli/22')
    })

    it('should mark the update item call as started', () => {
      stubbedUpdateStimulusCall()
      const updateCallStartAction = startCallFor(UPDATE_STIMULUS_CALL)
      checkActionDispatched(dispatchStub, updateCallStartAction)
    })

    it('should serialize data properly', () => {
      stubbedUpdateStimulusCall()
      const expectedData = JSON.stringify({
        stimulus: {
          title: 'stimulus title',
          instructions: 'stimulus instructions',
          body: 'stimulus body',
          source_url: 'stimulus sourceUrl'
        }
      })

      expect(
        fetchStub.getCall(0).args[1].body
      ).to.be.eql(expectedData)
    })

    const fakeUpdateStimulus = () => {
      const response = jsoniblePromise(stimulusData)
      const fakeFetch = makeFakeFetch(response)

      Fetcher.fakeFetch = fakeFetch
      const stimulus = new Stimulus(stimulusData)
      const updateStimulusThunk = updateStimulus(stimulus)
      return updateStimulusThunk(dispatchStub, getStateStub)
    }

    it('should mark the update call as a success on return', (done) => {
      const fetchPromise = fakeUpdateStimulus()
      const successfulUpdate = successCallFor(UPDATE_STIMULUS_CALL)
      fetchPromise.then(() => {
        checkActionDispatched(dispatchStub, successfulUpdate)
        done()
      })
    })

    it('should try to update the stimulus in the store', (done) => {
      const fetchPromise = fakeUpdateStimulus()
      const handleStimulusAction = addStimuli([stimulusData])
      fetchPromise.then(() => {
        checkActionDispatched(dispatchStub, handleStimulusAction)
        done()
      })
    })
  })
})
