import createShallowTestbed from '../../../../../tests/util/shallowTestbed'
import AddToBankModal from '../presenter'
import Bank from '../../../../common/records/Bank'
import { TEMPORARY_BANK_ID } from '@instructure/quiz-common/lib/constants'
import BankSelection from '../../../../common/components/resources/BankSelection'
import Modal from '@instructure/ui-overlays/lib/components/Modal'

describe('AddToBankModal', () => {
  const label = 'This is my modal'
  const closeModalStub = sinon.stub()
  const onContinueStub = sinon.stub()
  const focusStub = sinon.stub()
  const createBankStub = sinon.stub().returns(Promise.resolve({ id: '33' }))
  const createBankEntryStub = sinon.spy((bankId, entryType, entryId) => {
    return Promise.resolve({ id: '22', bankId, entryType, entryId })
  })
  const getEntryStub = sinon.stub().returns(Promise.resolve({ id: '44' }))
  const onAddStub = sinon.stub()
  const uiSet = sinon.stub()

  const modalProps = {
    closeModal: closeModalStub,
    createBank: createBankStub,
    createBankEntry: createBankEntryStub,
    entryId: '44',
    entryType: 'Item',
    getEntry: getEntryStub,
    label: label,
    modalOpen: true,
    onAdd: onAddStub,
    onContinue: onContinueStub,
    selectedBank: new Bank({ id: TEMPORARY_BANK_ID }),
    uiSet: uiSet,
    modalTrigger: {
      focus: focusStub
    }
  }
  const shallowTestbed = createShallowTestbed(AddToBankModal, modalProps)

  beforeEach(() => {
    closeModalStub.resetHistory()
    focusStub.resetHistory()
    createBankStub.resetHistory()
    createBankEntryStub.resetHistory()
    getEntryStub.resetHistory()
    onAddStub.resetHistory()
    uiSet.resetHistory()
  })

  describe('AddToBankModal', () => {
    it('renders the modal', () => {
      shallowTestbed.render()
      const modal = shallowTestbed.find(Modal)
      expect(modal).to.have.length(1)
    })
  })

  describe('Modal Title', () => {
    it('renders the correct title for the modal', () => {
      shallowTestbed.render()
      const modalheader = shallowTestbed.find('ModalHeader')
      expect(modalheader).to.have.length(1)
      expect(modalheader.render().text()).to.be.equal(label)
    })
  })

  describe('bank type radios', () => {
    it('change the bankType based on the radio selection', () => {
      shallowTestbed.render()
      const radioGroup = shallowTestbed.find('RadioInputGroup').first()
      radioGroup.prop('onChange')(null, 'new')
      expect(shallowTestbed.subject.state('bankType')).to.equal('new')
    })
  })

  context('using an existing bank', () => {
    it('renders selection for bank', () => {
      shallowTestbed.render()
      const bankInput = shallowTestbed.find(BankSelection)
      expect(bankInput.length).to.equal(1)
    })

    it('calls uiSet on bank selection', () => {
      shallowTestbed.render()
      const bankSelection = shallowTestbed.find(BankSelection)
      bankSelection.props().onBankSelection({}, {value: 'bank'})
      expect(uiSet).to.have.been.calledWith('ADD_TO_BANK_MODAL_BANK_SELECTION', 'bank')
    })
  })

  context('using a new bank', () => {
    it('renders an input for the new bank title', () => {
      const subject = shallowTestbed.render()
      subject.setState({ bankType: 'new' })
      const textInput = shallowTestbed.find('TextInput')
      expect(textInput.length).to.equal(1)
    })

    it('updates the state when the input changes', () => {
      const subject = shallowTestbed.render()
      subject.setState({ bankType: 'new' })
      const textInput = shallowTestbed.find('TextInput').first()
      textInput.prop('onChange')({ target: { value: 'some new title' } })
      expect(subject.state('newBankTitle')).to.equal('some new title')
    })
  })

  describe('Cancel action', () => {
    it('renders cancel button', () => {
      shallowTestbed.render()
      const cancelButton = shallowTestbed.find('Button[variant="default"]')
      expect(cancelButton.render().text()).to.include('Cancel')
    })

    it('calls the cancel action', () => {
      shallowTestbed.render()
      const cancelButton = shallowTestbed.find('Button[variant="default"]')
      shallowTestbed.click(cancelButton)
      expect(closeModalStub).to.be.called()
    })
  })

  describe('Add to Bank action', () => {
    const submit = (testbed) => {
      const addToBankButton = testbed.find('Button[variant="primary"]')
      testbed.click(addToBankButton)
    }

    it('renders the add to bank button', () => {
      shallowTestbed.render()
      const modalfooter = shallowTestbed.find('ModalFooter')
      const addToBankButton = modalfooter.shallow({disableLifecycleMethods: true}).find('Button[variant="primary"]')
      expect(addToBankButton.render().text()).to.include('Add')
    })

    it('renders a disabled button if there is no title for the new bank', () => {
      const subject = shallowTestbed.render()
      subject.setState({ bankType: 'new', newBankTitle: '   ' })
      const addToBankButton = shallowTestbed.find('Button[variant="primary"]')
      expect(addToBankButton.prop('disabled')).to.be.true()
    })

    describe('add', () => {
      const addTestbed = createShallowTestbed(AddToBankModal, {
        ...modalProps,
        selectedBank: new Bank({ id: '1' })
      })

      it('closes modal', () => {
        addTestbed.render()
        submit(addTestbed)
        expect(closeModalStub).to.have.been.called()
      })

      it('calls onContinue', () => {
        addTestbed.render()
        submit(addTestbed)
        expect(onContinueStub).to.have.been.called()
      })

      it('creates a new bank if needed', () => {
        const subject = shallowTestbed.render()
        subject.setState({ bankType: 'new', newBankTitle: 'my cool title' })
        submit(shallowTestbed)
        expect(createBankStub).to.have.been.called()
      })

      it('does not create a new bank if not needed', () => {
        addTestbed.render()
        submit(addTestbed)
        expect(createBankStub).to.have.not.been.called()
      })

      it('creates bank entry in the bank', (done) => {
        addTestbed.render()
        submit(addTestbed)
        setTimeout(() => {
          expect(createBankEntryStub).to.have.been.calledWith('1', 'Item', '44')
          done()
        }, 0)
      })

      it('allows parent to find item for bank', () => {
        addTestbed.render()
        submit(addTestbed)
        expect(getEntryStub).to.have.been.called()
      })

      it('calls onAdd with created bank entry', (done) => {
        addTestbed.render()
        submit(addTestbed)
        setTimeout(() => {
          expect(onAddStub).to.have.been.calledWith({ bankId: '1', id: '22', entryId: '44', entryType: 'Item' })
          done()
        }, 0)
      })
    })
  })
})
