import { Set, List } from 'immutable'

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

import DeleteStimulusModal from '../presenter'
import ConnectedDeleteStimulusModal from '../index'
import styles from '../styles.css'

import {
  DELETE_STIMULUS_MODAL_SELECTED_CHILDREN,
  DELETE_STIMULUS_MODAL_DELETION_MODE
} from '@instructure/quiz-common/lib/constants'

describe('DeleteStimulasModal', () => {
  const closeModalStub = sinon.stub()
  const removeStimulusStub = sinon.stub()
  const setUiStub = sinon.stub()
  const withConfirmStub = sinon.stub()

  const stimulusEntry = new QuizEntry()
  const stimulus = new Stimulus()
  stimulusEntry.getEntry = () => stimulus

  const itemEntry1 = new QuizEntry({id: '201'})
  const item1 = new Item({id: '301', itemBody: '<p>aaa</p>'})
  itemEntry1.getEntry = () => item1
  item1.quizEntry = itemEntry1

  const itemEntry2 = new QuizEntry({id: '202'})
  const item2 = new Item({id: '302', itemBody: 'bbb'})
  itemEntry2.getEntry = () => item2
  item2.quizEntry = itemEntry2

  const itemEntry3 = new QuizEntry({id: '203'})
  const item3 = new Item({id: '303', itemBody: 'ccc'})
  itemEntry3.getEntry = () => item3
  item3.quizEntry = itemEntry3

  const defaultProps = {
    childEntries: List([itemEntry1, itemEntry2, itemEntry3]),
    closeModal: closeModalStub,
    deletionMode: null,
    modalOpen: true,
    quizId: '456',
    removeStimulus: removeStimulusStub,
    selectedChildren: Set.of(),
    setUi: setUiStub,
    stimulusEntry,
    withConfirm: withConfirmStub
  }

  const testbed = createTestbed(withContext(DeleteStimulusModal), defaultProps)

  afterEach(() => {
    closeModalStub.resetHistory()
    removeStimulusStub.resetHistory()
    setUiStub.resetHistory()
  })

  const getModal = () => window.document.querySelector(`.${styles.deleteStimulusModal}`)
  const submit = () => {
    const button = window.document.querySelectorAll('button')[2]
    expect(button.innerText).to.eq('Submit')
    button.click()
  }

  context('zero children', () => {
    it('renders no options', () => {
      testbed.render({childEntries: List([])})
      const inputs = getModal().querySelectorAll('input[type=radio]')
      expect(inputs.length).to.eq(0)
    })
  })

  context('one child', () => {
    it('renders only two options', () => {
      testbed.render({childEntries: List([itemEntry1])})
      const inputs = getModal().querySelectorAll('input[type=radio]')
      expect(inputs.length).to.eq(2)
    })
  })

  context('multiple children', () => {
    it('renders three input buttons', () => {
      testbed.render()
      const inputs = getModal().querySelectorAll('input[type=radio]')
      expect(inputs.length).to.eq(3)
    })

    it('sets the deletion mode to deleteAll when option is selected', () => {
      testbed.render()
      const inputs = getModal().querySelectorAll('input[type=radio]')
      inputs[0].click()
      expect(setUiStub.calledWith(DELETE_STIMULUS_MODAL_DELETION_MODE, 'deleteAll'))
    })

    it('deletes all children when deleteAll option is selected', () => {
      testbed.render({deletionMode: 'deleteAll'})
      submit()
      expect(removeStimulusStub.calledWith('456', stimulusEntry, defaultProps.childEntries))
    })

    it('does not show checkboxes when deleteAll option is selected', () => {
      testbed.render({deletionMode: 'deleteAll'})
      const checkboxes = getModal().querySelectorAll('input[type=checkbox]')
      expect(checkboxes.length).to.eq(0)
    })

    it('sets the deletion mode to deleteNone when option is selected', () => {
      testbed.render()
      const inputs = getModal().querySelectorAll('input[type=radio]')
      inputs[2].click()
      expect(setUiStub.calledWith(DELETE_STIMULUS_MODAL_DELETION_MODE, 'deleteNone'))
    })

    it('deletes no children when deleteNone option is selected', () => {
      testbed.render({deletionMode: 'deleteNone'})
      submit()
      expect(removeStimulusStub.calledWith('456', stimulusEntry, []))
    })

    it('does not show checkboxes when deleteNone option is selected', () => {
      testbed.render({deletionMode: 'deleteNone'})
      const checkboxes = getModal().querySelectorAll('input[type=checkbox]')
      expect(checkboxes.length).to.eq(0)
    })

    it('sets the deletion mode to chooseWhich when option is selected', () => {
      testbed.render()
      const inputs = getModal().querySelectorAll('input[type=radio]')
      inputs[1].click()
      expect(setUiStub.calledWith(DELETE_STIMULUS_MODAL_DELETION_MODE, 'chooseWhich'))
    })

    it('renders checkboxes when chooseWhich option is selected', () => {
      testbed.render({deletionMode: 'chooseWhich'})
      const checkboxes = getModal().querySelectorAll('input[type=checkbox]')
      expect(checkboxes.length).to.eq(defaultProps.childEntries.size)
    })

    it('renders the stems of each question when chooseWhich option is selected', () => {
      testbed.render({deletionMode: 'chooseWhich'})
      const inputs = getModal().querySelectorAll('input[type=checkbox]')
      const stems = Array.from(inputs, (input) => input.labels[0].innerText.trim())
      expect(stems).to.deep.eq(['aaa', 'bbb', 'ccc'])
    })

    it('tries to add a child entry when checkbox is checked', () => {
      testbed.render({deletionMode: 'chooseWhich', selectedChildren: Set.of()})
      const checkboxes = getModal().querySelectorAll('input[type=checkbox]')
      expect(checkboxes[0].checked).to.be.false()
      checkboxes[0].click()

      const args = setUiStub.firstCall.args
      expect(args[0]).to.eq(DELETE_STIMULUS_MODAL_SELECTED_CHILDREN)
      expect(args[1].equals(Set.of(itemEntry1))).to.be.true()
    })

    it('tries to remove a child entry when checkbox is unchecked', () => {
      testbed.render({deletionMode: 'chooseWhich', selectedChildren: Set.of(itemEntry1)})
      const checkboxes = getModal().querySelectorAll('input[type=checkbox]')
      expect(checkboxes[0].checked).to.be.true()
      checkboxes[0].click()

      const args = setUiStub.firstCall.args
      expect(args[0]).to.eq(DELETE_STIMULUS_MODAL_SELECTED_CHILDREN)
      expect(args[1].equals(Set.of())).to.be.true()
    })

    it('submits the form with the selected items to delete', () => {
      testbed.render({
        deletionMode: 'chooseWhich',
        selectedChildren: Set.of(itemEntry1, itemEntry2)
      })
      submit()

      expect(removeStimulusStub.calledWith('456', stimulusEntry, [itemEntry1.id, itemEntry2.id]))
    })

    it('opens a confirmation modal if keeping immutable items', () => {
      const immutableQuizEntry = new QuizEntry({status: 'immutable'})
      testbed.render({
        childEntries: List([immutableQuizEntry]),
        deletionMode: 'deleteNone'
      })
      submit()
      expect(withConfirmStub).to.have.been.called()
    })
  })

  describe('#anyImmutableKeepers', () => {
    it('returns true if at least one child entry which will be kept in quiz is immutable', () => {
      const immutableQuizEntry = new QuizEntry({status: 'immutable'})
      const mutableQuizEntry = new QuizEntry({status: 'mutable'})
      testbed.render({
        childEntries: List([immutableQuizEntry, mutableQuizEntry]),
        selectedChildren: Set([mutableQuizEntry])
      })
      const modal = testbed.findChildrenByType(DeleteStimulusModal)[0]
      expect(modal.anyImmutableKeepers()).to.be.true()
    })

    it('returns false if all kept entries are mutable', () => {
      const immutableQuizEntry = new QuizEntry({status: 'immutable'})
      const mutableQuizEntry = new QuizEntry({status: 'mutable'})
      testbed.render({
        childEntries: List([immutableQuizEntry, mutableQuizEntry]),
        selectedChildren: Set([immutableQuizEntry])
      })
      const modal = testbed.findChildrenByType(DeleteStimulusModal)[0]
      expect(modal.anyImmutableKeepers()).to.be.false()
    })
  })

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

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

    shouldRenderComponent(
      connectedTestbed, {}, DeleteStimulusModal
    )
  })
})
