import { expect } from 'chai'
import { is, List, fromJS } from 'immutable'

import {
  singleRelationCheck,
  manyRelationCheck
} from '../../../../tests/util/recordTests'

import {setFakeStore, unsetFakeStore} from '../../../reduxStore'

import Quiz from '../Quiz'
import QtiImport from '../QtiImport'
import QuizEntry from '../QuizEntry'
import QuizSession from '../QuizSession'

describe('Quiz Record', () => {
  describe('#constructor', () => {
    it('defaults shuffleQuestions to false', () => {
      expect(new Quiz().shuffleQuestions).to.be.false()
    })
  })

  describe('isOneQuestionAtATime', () => {
    it('is true when quiz has oneAtATimeType "question"', () => {
      expect(new Quiz({oneAtATimeType: 'question'}).isOneQuestionAtATime())
        .to.be.true()
    })

    it('is false when quiz does not have oneAtATimeType "question"', () => {
      expect(new Quiz({oneAtATimeType: null}).isOneQuestionAtATime())
        .to.be.false()
    })
  })

  describe('#getTimeLimit', () => {
    context('hasTimeLimit not set', () => {
      it('returns 0', () => {
        const quiz = new Quiz({hasTimeLimit: false, sessionTimeLimitInSeconds: 100})
        expect(quiz.getTimeLimit()).to.eq(0)
      })
    })

    context('hasTimeLimit set', () => {
      context('sessionTimeLimitInSeconds set', () => {
        it('returns the correct time limit', () => {
          const quiz = new Quiz({hasTimeLimit: true, sessionTimeLimitInSeconds: 100})
          expect(quiz.getTimeLimit()).to.eq(100)
        })
      })

      context('sessionTimeLimitInSeconds not set', () => {
        it('returns null', () => {
          const quiz = new Quiz({hasTimeLimit: true})
          expect(quiz.getTimeLimit()).to.eq(null)
        })
      })
    })
  })

  describe('#isLoaded', () => {
    it('returns true if id is not \'0\'', () => {
      const quiz = new Quiz({id: '1'})
      expect(quiz.isLoaded()).to.be.true()
    })

    it('returns false if id is \'0\'', () => {
      const quiz = new Quiz({id: '0'})
      expect(quiz.isLoaded()).to.be.false()
    })
  })

  describe('#isImporting', () => {
    it('returns true if status is "importing"', () => {
      const quiz = new Quiz({status: 'importing'})
      expect(quiz.isImporting()).to.be.true()
    })

    it('returns false otherwise', () => {
      const quiz = new Quiz()
      expect(quiz.isImporting()).to.be.false()
    })
  })

  describe('#canImport', () => {
    it('returns true if status is "uninitialized" and there are no quizEntries', () => {
      const quiz = new Quiz({status: 'uninitialized', quizEntries: List()})
      expect(quiz.canImport()).to.be.true()
    })

    it('returns false if status is not "uninitialized"', () => {
      const quiz = new Quiz({status: 'unpublished', quizEntries: []})
      expect(quiz.canImport()).to.be.false()
    })

    it('returns false a quizEntry is associated to it', () => {
      const quiz = new Quiz({status: 'uninitialized', quizEntries: ['2']})
      expect(quiz.canImport()).to.be.false()
    })
  })

  describe('#getWorkingInstance', () => {
    it('merges the right modifications into itself', () => {
      const modifiedTitle = 'Quick Quiz 1'
      setFakeStore(
        fromJS({
          modifications: {quizzes: {22: {id: '22', title: modifiedTitle}}}
        })
      )
      const quiz = new Quiz({id: '22'})
      expect(quiz.getWorkingInstance().title).to.be.equal(modifiedTitle)
      unsetFakeStore()
    })
  })

  describe('relationships', () => {
    const quizId = '1'
    describe('#getQuizSessions', () => {
      const exampleState = {
        quizSessions: {3: {id: '3', quiz: quizId}}
      }

      const options = {
        RelationRecordType: QuizSession,
        relationAttrs: {id: '3', quiz: quizId},
        recordAttributes: {id: quizId},
        necessaryState: fromJS(exampleState)
      }

      manyRelationCheck(Quiz, 'getQuizSessions', options)
    })

    describe('#getQuizSessionsForUser', () => {
      it('only returns sessions that match the given id', () => {
        const userId = '42'
        const goodSessionAttrs = {id: '3', quiz: quizId, user: {id: userId}}
        const badSessionAttrs = {id: '4', quiz: quizId, user: {id: '999'}}
        const quizSessionsForUser = List([goodSessionAttrs, badSessionAttrs].map((sessionData) => {
          return new QuizSession(fromJS(sessionData))
        }))

        const quiz = new Quiz({id: quizId})
        sinon.stub(quiz, 'getQuizSessions').returns(quizSessionsForUser)

        const foundSessionsForUser = quiz.getQuizSessionsForUser(userId)
        expect(foundSessionsForUser.size).to.be.equal(1)
        expect(
          is(quizSessionsForUser.first(), foundSessionsForUser.first())
        ).to.be.true()
      })
    })

    describe('#getQuizEntries', () => {
      const qiAttrs = {id: '3', entry: '2', quiz: quizId}
      const exampleState = {
        quizEntries: {3: qiAttrs}
      }

      const options = {
        RelationRecordType: QuizEntry,
        relationAttrs: qiAttrs,
        recordAttributes: {id: quizId, quizEntries: ['3']},
        necessaryState: fromJS(exampleState)
      }

      manyRelationCheck(Quiz, 'getQuizEntries', options)
    })

    describe('#getLatestImport', () => {
      const laterImportData = {parentId: quizId, parentType: 'Quiz', id: '2'}
      const exampleState = {
        qtiImports: {
          1: {parentId: quizId, parentType: 'Quiz', id: '1'},
          2: laterImportData
        }
      }

      const options = {
        RelationRecordType: QtiImport,
        relationAttrs: laterImportData,
        recordAttributes: {id: quizId},
        necessaryState: fromJS(exampleState)
      }

      singleRelationCheck(Quiz, 'getLatestImport', options)
    })
  })

  describe('#isOneQuestionAtATime', () => {
    it('returns true if not null value for oneAtATimeType', () => {
      const quiz = new Quiz({oneAtATimeType: 'question'})
      expect(quiz.isOneQuestionAtATime()).to.eq(true)
    })

    it('returns false if null value for oneAtATimeType', () => {
      const quiz = new Quiz({oneAtATimeType: null})
      expect(quiz.isOneQuestionAtATime()).to.eq(false)
    })
  })
})
