import Checkbox from '@instructure/ui-forms/lib/components/Checkbox'

import createShallowTestbed from '../../../../../tests/util/shallowTestbed'
import CopyMoveBankEntryModal from '../presenter'
import Bank from '../../../../common/records/Bank'
import BankSelection from '../../../../common/components/resources/BankSelection'
import Modal from '@instructure/ui-overlays/lib/components/Modal'

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

  const modalProps = {
    closeModal: closeModalStub,
    createBank: createBankStub,
    createBankEntry: createBankEntryStub,
    createEntry: createEntryStub,
    disassociateBankEntry: disassociateBankEntry,
    entryId: '44',
    entryType: 'Item',
    label: label,
    modalOpen: true,
    onAdd: onAddStub,
    selectedBank: new Bank({ id: '0' }),
    uiSet: uiSet,
    updateBankEntry: updateBankEntryStub,
    modalTrigger: {
      focus: focusStub
    }
  }
  const shallowTestbed = createShallowTestbed(CopyMoveBankEntryModal, modalProps)

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

  describe('CopyMoveBankEntryModal', () => {
    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('COPY_MOVE_BANK_ENTRY_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('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()
    })

    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('keep copy checkbox', () => {
    it('renders keep copy checkbox when source bank entry is present', () => {
      shallowTestbed.render({ sourceBankId: '1', sourceBankEntryId: '1' })
      const keepCopyInput = shallowTestbed.find('Checkbox')
      expect(keepCopyInput.render().text()).to.include('Keep a copy in this bank')
    })
  })

  describe('onKeepCopyChange', () => {
    it('calls uiSet', () => {
      shallowTestbed.render()
      const checkbox = shallowTestbed.find(Checkbox)
      checkbox.props().onChange({target: {checked: true}})
      expect(uiSet).to.have.been.calledWith('COPY_MOVE_BANK_ENTRY_MODAL_KEEP_COPY', true)
    })
  })

  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()
      expect(focusStub).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')
    })

    describe('copy', () => {
      const copyTestbed = createShallowTestbed(CopyMoveBankEntryModal, {
        ...modalProps,
        selectedBank: new Bank({ id: '1' }),
        keepCopy: true,
        sourceBankId: '2',
        sourceBankEntryId: '3'
      })

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

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

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

      it('allows parent to create item for bank', () => {
        copyTestbed.render()
        submit(copyTestbed)
        expect(createEntryStub).to.have.been.called()
      })

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

    describe('move', () => {
      const moveTestbed = createShallowTestbed(CopyMoveBankEntryModal, {
        ...modalProps,
        selectedBank: new Bank({ id: '1' }),
        keepCopy: false,
        sourceBankId: '2',
        sourceBankEntryId: '3'
      })

      it('updates bank entry to selected bank', (done) => {
        moveTestbed.render()
        submit(moveTestbed)
        setTimeout(() => {
          expect(updateBankEntryStub).to.have.been.calledWith('2', '3', { bankId: '1' })
          done()
        }, 0)
      })

      it('calls onAdd with updated bank entry', (done) => {
        moveTestbed.render()
        submit(moveTestbed)
        setTimeout(() => {
          expect(onAddStub).to.have.been.calledWith(sinon.match({ bankId: '1', id: '3' }))
          done()
        }, 0)
      })
    })
  })
})
