import React from 'react'
import { List, Map } from 'immutable'

import Stimulus from '../../../../../records/Stimulus'
import QuizEntry from '../../../../../records/QuizEntry'
import Item from '../../../../../records/Item'

import StimulusPresenter from '../presenter'
import StimulusShow from '../../StimulusShow'
import StimulusEdit from '../../StimulusEdit'
import ConnectedStimulus from '../index'

import WarningWrapper from '../../../WarningWrapper'
import AddContentPopover from '../../../quiz/AddContent/Popover'

import ConnectedQuizEntry from '../../../../../../building/components/resources/quizEntry/QuizEntry'

import {
  DELETE_STIMULUS_DATA
} from '@instructure/quiz-common/lib/constants'

describe('Common Main Body Stimulus ', () => {
  const clearModificationsStub = sinon.stub()
  const openDeleteStimulusModalStub = sinon.stub()
  const setUiStub = sinon.stub()
  const switchOnEditingStub = sinon.stub()
  const switchOffEditingStub = sinon.stub()

  const quizEntry = new QuizEntry({
    id: '33',
    entryType: 'Stimulus',
    entry: '55',
    position: 5
  })

  sinon.stub(quizEntry, 'getEntry').returns(new Item())

  const propsForQuizEntryStub = sinon.stub().returns({
    quizEntries: List(),
    quizEntry: quizEntry,
    entry: new Item()
  })

  const stimulus = new Stimulus({
    id: '55',
    title: 'Title',
    instructions: 'Instructions',
    body: 'Body',
    sourceUrl: 'Source URL'
  })

  const defaultProps = {
    childEntries: List(),
    clearModifications: clearModificationsStub,
    deleteStimulusButton: <div className="fakeDeleteButton" />,
    displayPosition: 3,
    propsForQuizEntry: propsForQuizEntryStub,
    openDeleteStimulusModal: openDeleteStimulusModalStub,
    quizEntry,
    quizEntries: List(),
    quizId: '456',
    setUi: setUiStub,
    shouldClone: false,
    stimulus,
    switchOffEditing: switchOffEditingStub,
    switchOnEditing: switchOnEditingStub,
    updateStimulus: () => new Promise(() => {}),
    guid: 'iamunique'
  }

  const testbed = createTestbed(
    wrapInDragAndDropTestContext(
      withContext(StimulusPresenter)
    ), defaultProps
  )

  afterEach(() => {
    clearModificationsStub.resetHistory()
    openDeleteStimulusModalStub.resetHistory()
    propsForQuizEntryStub.resetHistory()
    setUiStub.resetHistory()
    switchOnEditingStub.resetHistory()
    switchOffEditingStub.resetHistory()
  })

  context('with children', () => {
    const qe1 = new QuizEntry({ id: '1', position: 6, entryType: 'Item' })
    const qe2 = new QuizEntry({ id: '2', position: 7, entryType: 'Item' })
    const bankQuizEntry = new QuizEntry({
      entryType: 'Bank',
      properties: Map({ sampleNum: 3 })
    })

    const quizEntries = [qe1, qe2, bankQuizEntry]
    quizEntries.forEach((qe) => {
      sinon.stub(qe, 'getEntry').returns(new Item())
    })

    const fakePropsForQuizEntry = (quizEntry, displayPosition) => {
      return {
        quizEntries: List(),
        quizEntry: quizEntry
      }
    }

    const render = (props = {}) => {
      testbed.render({
        childEntries: List([qe1, qe2]),
        propsForQuizEntry: fakePropsForQuizEntry,
        ...props
      })
    }

    it('renders child entries', () => {
      render()
      const childEntries = testbed.findChildrenByType(ConnectedQuizEntry)
      expect(childEntries.length).to.equal(2)
    })

    it('renders with the correct display positions', () => {
      testbed.render({
        childEntries: List([bankQuizEntry, qe1])
      })
      expect(propsForQuizEntryStub).to.have.been.calledTwice()
      expect(propsForQuizEntryStub.getCall(0).args[1]).to.equal(3)
      expect(propsForQuizEntryStub.getCall(1).args[1]).to.equal(6)
    })

    it('renders an AddContentPopover with the correct position', () => {
      render()
      const elem = testbed.findChildrenByType(AddContentPopover)[1]
      expect(elem).to.not.be.undefined()
      expect(elem.props.position).to.eq(8)
    })

    it('renders an AddContentPopover for each quizEntry', () => {
      render()
      expect(testbed.findChildrenByType(AddContentPopover).length).to.eq(2)
    })

    it('renders no AddContentPopover between questions when isOver is true', () => {
      render({ draggingOnBuild: true })
      expect(testbed.findChildrenByType(AddContentPopover).length).to.eq(0)
    })

    it('creates an openDeleteStimulusModal callback', () => {
      render()
      const elem = testbed.findChildByType(StimulusShow)
      elem.props.openDeleteStimulusModal()

      const args = setUiStub.firstCall.args
      expect(args[0]).to.eq(DELETE_STIMULUS_DATA)
      const data = args[1].toObject()
      expect(data.quizId).to.eq('456')
      expect(data.stimulusEntry).to.eql(quizEntry)
      expect(data.childEntries.toArray()).to.eql([qe1, qe2])
      expect(openDeleteStimulusModalStub.called).to.be.true()
    })
  })

  it('renders a StimulusShow component when editing is off', () => {
    testbed.render({isEditing: false})
    const elem = testbed.findChildByType(StimulusShow)
    expect(elem).to.not.be.undefined()
  })

  it('renders a StimulusEdit component when editing is on', () => {
    testbed.render({isEditing: true})
    const elem = testbed.findChildByType(StimulusEdit)
    expect(elem).to.not.be.undefined()
  })

  it('renders the StimulusEdit component with the working stimulus', () => {
    const workingStimulus = stimulus.merge({title: 'working stimulus title'})
    sinon.stub(stimulus, 'getWorkingInstance').returns(workingStimulus)
    testbed.render({stimulus: workingStimulus, isEditing: true})
    const elem = testbed.findChildByType(StimulusEdit)
    expect(elem.props.stimulus.title).to.eq('working stimulus title')
    stimulus.getWorkingInstance.restore()
  })

  it('does not render an immutability warning wrapper when banked', () => {
    testbed.render({isBankedContent: true})
    const wrappers = testbed.findChildrenByType(WarningWrapper)
    expect(wrappers.length).to.equal(0)
  })

  describe('test with connect', () => {
    const connectedTestbed = createTestbed(
      wrapInDragAndDropTestContext(withContext(ConnectedStimulus)),
      defaultProps
    )

    shouldRenderComponent(
      connectedTestbed, {}, StimulusPresenter
    )
  })
})
