import Fetcher from '../../util/Fetcher'
import { jsoniblePromise } from '../../util/jsonify'

import makeFakeFetch from '../../../../tests/util/fakeFetch'

import {
  fetchSessionItems,
  fetchQuizSessionResult,
  fetchQuizSession,
  fetchResumeData,
  fetchSessionItemResults,
  fetchTime,
  recordTime,
  pinSessionItem,
  singleResponseSubmit,
  submitStudentAccessCode,
  submitQuizSession,
  takeQuizSession
} from '../quizSessions'

import {
  handleQuizSessionResponse
} from '../callHandlers'

describe('quizSessions api actions', () => {
  const quizSessionId = '22'
  const fetchStub = sinon.stub()
  const dispatchStub = sinon.stub()
  const getStateStub = sinon.stub()
  const callBackStub = sinon.stub()
  afterEach(() => {
    callBackStub.resetHistory()
  })

  useFakeFetching({dispatchStub, getStateStub, fetchStub})

  const actAsApiCall = (apiCallHandler, urlParts, expectedUrl) => {
    it('hits the correct url', () => {
      Fetcher.fakeFetch = fetchStub

      apiCallHandler(...urlParts)
      expect(fetchStub.getCall(0).args[0]).to.contain(expectedUrl)
    })

    it('calls the callback', async () => {
      const response = [{faktFetch: 33}]
      Fetcher.fakeFetch = makeFakeFetch(jsoniblePromise(response))
      await apiCallHandler(...urlParts, new Promise(() => callBackStub()))
      expect(callBackStub.calledOnce).to.be.true()
    })
  }

  describe('fetchQuizSession', () => {
    actAsApiCall(fetchQuizSession, [22], '/api/quiz_sessions/22')
  })

  describe('fetchSessionItems', () => {
    actAsApiCall(fetchSessionItems, [22, 'session_items'], '/api/quiz_sessions/22/session_items')
  })

  describe('takeQuizSession', () => {
    actAsApiCall(takeQuizSession, [22], '/api/quiz_sessions/22/take')
  })

  describe('fetchResumeData', () => {
    actAsApiCall(fetchResumeData, [22], '/api/quiz_sessions/22/session_item_responses/resume_data')
  })

  describe('fetchTime', () => {
    actAsApiCall(fetchTime, [22], '/api/quiz_sessions/22/time')
  })

  describe('recordTime', () => {
    actAsApiCall(recordTime, [22], '/api/quiz_sessions/22/record')
  })

  describe('singleResponseSubmit', () => {
    actAsApiCall(singleResponseSubmit, [22], '/api/quiz_sessions/22/session_item_responses/single_response_submit')
  })

  describe('submitQuizSession', () => {
    actAsApiCall(submitQuizSession, [22], '/api/quiz_sessions/22/submit')
  })

  describe('fetchSessionItemResults', () => {
    actAsApiCall(fetchSessionItemResults, [22, 1], '/api/quiz_sessions/22/results/1/session_item_results')
  })

  describe('fetchQuizSessionResult', () => {
    actAsApiCall(fetchQuizSessionResult, [22, 1], '/api/quiz_sessions/22/results/1')
  })

  describe('submitStudentAccessCode', () => {
    actAsApiCall(submitStudentAccessCode, [22, 'code'], '/api/quiz_sessions/22/submit_student_access_code')
  })

  describe('pinSessionItem', () => {
    it('hits the correct url', () => {
      const expectedUrl = '/api/quiz_sessions/22/toggle_session_item_pin'
      Fetcher.fakeFetch = fetchStub

      pinSessionItem(quizSessionId, 11)(dispatchStub, getStateStub)
      expect(fetchStub.getCall(0).args[0]).to.eq(expectedUrl)
    })

    it('adds a quiz session response on success', async () => {
      const fakeQuizSessionResult = {id: '22', takingData: {pins: [11]}}
      const stubbedPinSessionItemCall = () => {
        const response = jsoniblePromise(fakeQuizSessionResult)
        Fetcher.fakeFetch = makeFakeFetch(response)
        return pinSessionItem('22', 11)(dispatchStub, getStateStub)
      }

      await stubbedPinSessionItemCall()
      const expectedResponse = handleQuizSessionResponse(fakeQuizSessionResult)
      checkActionDispatched(dispatchStub, expectedResponse[0])
    })
  })
})
