import { fromJS } from 'immutable'

import InteractionType from 'quiz-interactions/lib/records/InteractionType'
import ChoiceEditComponent from 'quiz-interactions/lib/components/multiple_choice/Edit'
import QuestionContainer from 'quiz-interactions/lib/components/common/edit/components/QuestionContainer'
import OutcomeCount from 'outcomes-react/lib/containers/OutcomeCount'
import Alert from '@instructure/ui-alerts/lib/components/Alert'

import ItemEdit from '../presenter'
import Item from '../../../../../records/Item'

describe('Item Edit', () => {
  const ItemWithContext = withContext(ItemEdit)
  const type = new InteractionType({ name: 'Multiple Choice', slug: 'choice' })
  const item = new Item({
    id: '666',
    title: 'Tough Color Question',
    itemBody: 'Which color is happiest?',
    scoringData: {
      value: 'id'
    },
    calculatorType: 'basic'
  })
  sinon.stub(item, 'getInteractionType').returns(type)
  const setShouldClone = sinon.stub()
  const changeItemStateStub = sinon.stub()
  const shouldClone = false

  const testbed = createTestbed(ItemWithContext, {
    entry: item,
    workingItem: item,
    setShouldClone,
    shouldClone,
    changeItemState: changeItemStateStub
  })

  afterEach(() => {
    changeItemStateStub.resetHistory()
    setShouldClone.resetHistory()
  })

  describe('#render', () => {
    it('renders the item body', () => {
      testbed.render()
      const textInput = testbed.findChildrenByType(QuestionContainer)[0]
      expect(textInput.props.itemBody).eq('Which color is happiest?')
    })

    it('renders the versioning alert when immutable', () => {
      const immutableItem = new Item({
        id: '666',
        title: 'Tough Color Question',
        itemBody: 'Which color is happiest?',
        scoringData: {
          value: 'id'
        },
        status: 'immutable'
      })
      const shallowTestbed = testbed.renderShallowly({item: immutableItem})
      const alert = shallowTestbed.find(Alert)
      expect(alert).to.not.be.undefined()
    })

    it('renders an error when there is a size error', () => {
      sinon.stub(item, 'getErrors').returns(fromJS({ onSelf: ['some error'] }))
      testbed.render({ errorsAreShowing: true })
      expect(testbed.getText()).to.include('some error')
    })

    it('passes the correct hidden options value when calculator per question is enabled', () => {
      testbed.render({
        showCalculator: true
      })
      const component = testbed.findChildByType(ChoiceEditComponent)
      expect(component.props.hiddenOptions).to.eql({
        calculator: false
      })
    })

    it('passes the correct hidden options value when calculator per question is not enabled', () => {
      testbed.render({
        showCalculator: false
      })
      const component = testbed.findChildByType(ChoiceEditComponent)
      expect(component.props.hiddenOptions).to.eql({
        calculator: true
      })
    })

    it('passes the correct oneQuestionAtATime value to the interaction', () => {
      testbed.render({
        oneQuestionAtATime: true
      })
      const component = testbed.findChildByType(ChoiceEditComponent)
      expect(component.props.oneQuestionAtATime).to.be.true()
    })
  })

  describe('includes the correct additional options', () => {
    it('does not include additional options by default', () => {
      testbed.render()
      const component = testbed.findChildByType(ChoiceEditComponent)
      expect(component.props.additionalOptions).to.have.length(0)
    })

    describe('with outcomes enabled', () => {
      it('does not include OutcomeAlignments when not configured', () => {
        testbed.render({
          isEditing: true
        })
        const component = testbed.findChildByType(ChoiceEditComponent)
        expect(component.props.additionalOptions).to.have.length(0)
      })

      describe('with outcomes configured', () => {
        beforeEach(() => {
          testbed.render({
            contextUuid: 'alphabeta',
            outcomesEndpoint: 'http://foo',
            outcomesToken: 'tokentoken'
          })
        })

        it('includes OutcomeAlignments', () => {
          const component = testbed.findChildByType(ChoiceEditComponent)
          expect(component.props.additionalOptions).to.have.length(1)
          expect(component.props.additionalOptions.map((opt) => opt.key)).to.include('outcomes')
        })

        it('should include an outcome count object', () => {
          expect(testbed.findChildrenByType(OutcomeCount)).not.to.have.length(0)
        })

        it('passes outcomes endpoint and token props', () => {
          const count = testbed.findChildrenByType(OutcomeCount)[0]
          expect(count.props.host).to.equal('http://foo')
          expect(count.props.jwt).to.equal('tokentoken')
          expect(count.props.contextUuid).to.equal('alphabeta')
          const component = testbed.findChildByType(ChoiceEditComponent)
          const alignments = component.props.additionalOptions.map((opt) => opt.component)[0]
          expect(alignments.props.host).to.equal('http://foo')
          expect(alignments.props.jwt).to.equal('tokentoken')
          expect(alignments.props.contextUuid).to.equal('alphabeta')
        })
      })
    })
  })

  describe('outcome modal handlers', () => {
    const modalHandlerStub = sinon.stub()
    const changeOutcomeAlignmentSetGuid = sinon.stub()
    beforeEach(() => {
      testbed.render({
        isEditing: true,
        occludeQuizEntries: modalHandlerStub,
        outcomesEndpoint: 'http://foo',
        changeOutcomeAlignmentSetGuid
      })
    })

    it('calls onOutcomeModalOpen', () => {
      const component = testbed.findChildByType(ChoiceEditComponent)
      const alignments = component.props.additionalOptions[0].component
      alignments.props.onModalOpen()
      expect(modalHandlerStub.called).to.be.true()
    })

    it('calls onOutcomeModalClose', () => {
      const component = testbed.findChildByType(ChoiceEditComponent)
      const alignments = component.props.additionalOptions[0].component
      alignments.props.onModalClose()
      expect(modalHandlerStub.called).to.be.true()
    })

    it('calls onOutcomeAlignmentSetChange', () => {
      const component = testbed.findChildByType(ChoiceEditComponent)
      const alignments = component.props.additionalOptions[0].component
      const outcomeAlignmentSet = {guid: 'abc'}
      alignments.props.onUpdate(outcomeAlignmentSet)
      expect(changeOutcomeAlignmentSetGuid.called).to.be.true()
    })
  })

  describe('a11y tests', () => {
    it('should meet a11y standards', (done) => {
      testbed.render()
      testbed.checkA11yStandards(done, {
        ignores: ['aria-required-children', 'label', 'label-title-only']
      })
    })
  })
})
