import { List } from 'immutable'
import ImportModal from '../presenter'
import createShallowTestbed from '../../../../../tests/util/shallowTestbed'

import {
  FILE_UPLOAD_SELECT,
  FILE_UPLOAD_IMPORTING,
  FILE_UPLOAD_SUCCESS,
  FILE_UPLOAD_FAILURE,
  FILE_UPLOAD_ERROR
} from '@instructure/quiz-common/lib/constants'

describe('ImportModal', () => {
  const sandbox = sinon.createSandbox()
  const setAltTextStub = sandbox.stub()
  const defaultProps = {
    acceptFileType: '.jpg, .png',
    altText: '',
    clearAltText: sandbox.stub(),
    clearFiles: sandbox.stub(),
    closeModal: sandbox.stub(),
    failureMessage: 'this is a failure message',
    files: List([{name: 'test1.jpg'}, {name: 'test2.jpg'}]),
    fileUpload: sandbox.stub(),
    importMessage: 'this is an import message',
    modalOpen: true,
    onContinue: sandbox.stub(),
    progressValue: 0,
    receiveFile: sandbox.stub(),
    setAltText: setAltTextStub,
    setUploadStatus: sandbox.stub(),
    uploadStatus: FILE_UPLOAD_SELECT
  }
  const testbed = createTestbed(withContext(ImportModal), defaultProps)
  const shallowTestbed = createShallowTestbed(ImportModal, defaultProps)

  afterEach(() => {
    sandbox.resetHistory()
  })

  const getModal = () => {
    return testbed.getRefs().composedComponent
  }

  const sharedCancelExample = (uploadStatus = FILE_UPLOAD_SELECT) => {
    it('clears the files and closes the modal on cancel', () => {
      testbed.click(getModal().cancelImportButton)
      expect(defaultProps.clearFiles.called).to.be.true()
      expect(defaultProps.closeModal.called).to.be.true()
    })
  }

  const sharedCancelDisabledExample = (uploadStatus = FILE_UPLOAD_FAILURE) => {
    it('sets the cancelButton to be disabled', () => {
      testbed.render({uploadStatus})
      expect(getModal().cancelImportButton.props.disabled).to.be.true()
    })
  }

  const sharedContinueButtonExample = ({
    uploadStatus = FILE_UPLOAD_SELECT,
    files = List([]),
    buttonText = 'Import',
    disabled = true
  } = {}) => {
    it(`disables the continueButton is ${disabled}`, () => {
      testbed.render({uploadStatus, files})
      expect(getModal().confirmButton.props.disabled).to.eq(disabled)
    })

    it(`has the text ${buttonText}`, () => {
      testbed.render({uploadStatus, files})
      expect(testbed.getText()).to.include(buttonText)
    })
  }

  describe('#componentDidUpdate', () => {
    function testComponentDidUpdate (states, shouldCall) {
      testbed.render(states[0])
      const instance = testbed.findChildByType(ImportModal)
      const continueActionStub = sinon.stub(instance, 'continueAction')
      expect(continueActionStub).to.not.have.been.called()
      testbed.render(states[1])
      if (shouldCall) {
        expect(continueActionStub).to.have.been.called()
      } else {
        expect(continueActionStub).to.not.have.been.called()
      }
    }

    it('Does not continue after filedrop', () => {
      testComponentDidUpdate([
        { files: List([]), disableConfirm: false },
        { files: List([{name: 'file1'}]), disableConfirm: false }
      ], false)
    })

    context('without disableConfirm', () => {
      it('Does not continue on sucessful upload', () => {
        testComponentDidUpdate([
          { uploadStatus: FILE_UPLOAD_IMPORTING, disableConfirm: false },
          { uploadStatus: FILE_UPLOAD_SUCCESS, disableConfirm: false }
        ], false)
      })
    })

    context('with disableConfirm', () => {
      it('Does continue on sucessful upload', () => {
        testComponentDidUpdate([
          { uploadStatus: FILE_UPLOAD_IMPORTING, disableConfirm: true },
          { uploadStatus: FILE_UPLOAD_SUCCESS, disableConfirm: true }
        ], true)
      })

      it('Does not continue on failed upload', () => {
        testComponentDidUpdate([
          { uploadStatus: FILE_UPLOAD_IMPORTING, disableConfirm: true },
          { uploadStatus: FILE_UPLOAD_FAILURE, disableConfirm: true }
        ], false)
      })

      it('Does not continue without change (file)', () => {
        const file = {name: 'file1'}
        testComponentDidUpdate([
          { files: List([file]), disableConfirm: true },
          { files: List([file]), disableConfirm: true }
        ], false)
      })

      it('Does not continue without change (upload)', () => {
        testComponentDidUpdate([
          { uploadStatus: FILE_UPLOAD_SUCCESS, disableConfirm: true },
          { uploadStatus: FILE_UPLOAD_SUCCESS, disableConfirm: true }
        ], false)
      })
    })
  })

  describe('rendering with tabs', () => {
    it('should not render tabs if a single acceptFileType string is given', () => {
      shallowTestbed.render({}, null, {disableLifecycleMethods: true})
      const tabs = shallowTestbed.find('TabPanel')
      expect(tabs.length).to.equal(0)
    })

    it('should render tabs if acceptFileType is a list of types', () => {
      shallowTestbed.render({
        acceptFileType: [
          { fileType: 'image/*', title: 'Image' },
          { fileType: 'audio/mp3, audio/wav, audio/ogg', title: 'Audio' },
          { fileType: 'video/mp4, video/webm, video/ogg', title: 'Video' }
        ]
      }, null, {disableLifecycleMethods: true})
      const tabs = shallowTestbed.find('TabPanel')
      expect(tabs.length).to.equal(3)
    })

    it('should update tab index on change', () => {
      const subject = shallowTestbed.render({
        acceptFileType: [
          { fileType: 'image/*', title: 'Image' },
          { fileType: 'audio/mp3, audio/wav, audio/ogg', title: 'Audio' },
          { fileType: 'video/mp4, video/webm, video/ogg', title: 'Video' }
        ]
      }, null, {disableLifecycleMethods: true})
      const tabList = shallowTestbed.find('TabList')
      tabList.simulate('change', 2)
      expect(subject.state('selectedTabIndex')).to.equal(2)
    })
  })

  describe('rendering with no file selected', () => {
    let confirmButtonSpy
    afterEach(() => {
      if (confirmButtonSpy) {
        confirmButtonSpy.restore()
        confirmButtonSpy = null
      }
    })

    it('renders a file selector', () => {
      testbed.render({files: List([])})
      const content = document.body.innerText
      expect(content).to.include('this is an import message')
      expect(content).to.include('Drag & Drop here')
      expect(content).to.include('Browse')
    })

    it('moves focus to the Import button when a file is selected', () => {
      testbed.render({files: List([])})
      const modal = getModal()
      confirmButtonSpy = sinon.spy(modal.confirmButton, 'focus')
      modal.fileSelector.props.receiveFile('FILE')
      expect(confirmButtonSpy).to.have.been.calledOnce()
    })

    it('shared examples', () => {
      testbed.render()
      sharedCancelExample()
      sharedContinueButtonExample()
    })

    context('when uploading an image', () => {
      it('calls setAltText on altText input change', () => {
        testbed.render({ acceptFileType: 'image/*' })
        const input = getModal().altTextInput
        input.props.onChange({target: {value: 'hi'}})
        expect(setAltTextStub).to.have.been.called()
      })
    })
  })

  describe('rendering with a selected file', () => {
    it('renders an active confirm button', () => {
      testbed.render()
      expect(getModal().confirmButton.props.disabled).to.be.false()
    })

    it('renders the selected file name', () => {
      testbed.render()
      const content = document.body.innerText
      expect(content).to.include('test1.jpg')
    })

    it('attempts to import on continue', () => {
      testbed.render()
      testbed.click(getModal().confirmButton)
      expect(defaultProps.fileUpload.called).to.be.true()
      expect(defaultProps.setUploadStatus.calledWith(FILE_UPLOAD_IMPORTING)).to.be.true()
      expect(defaultProps.onContinue.called).to.be.true()
    })

    it('shared examples', () => {
      testbed.render()
      sharedCancelExample()
      sharedContinueButtonExample({disabled: false, files: defaultProps.files})
    })
  })

  context('with an in progress import', () => {
    it('renders the importing progress', () => {
      testbed.render({uploadStatus: FILE_UPLOAD_IMPORTING})
      expect(getModal().progressBar).to.not.be.undefined()
    })

    it('updates the progress correctly', () => {
      testbed.render({uploadStatus: FILE_UPLOAD_IMPORTING, progressValue: 50})
      expect(getModal().progressBar.props.valueNow).to.eq(50)
    })

    it('shared examples', () => {
      testbed.render()
      sharedCancelExample(FILE_UPLOAD_IMPORTING)
      sharedContinueButtonExample({uploadStatus: FILE_UPLOAD_IMPORTING, files: defaultProps.files})
    })
  })

  context('the upload errors', () => {
    it('renders the upload error message', () => {
      testbed.render({uploadStatus: FILE_UPLOAD_ERROR})
      const alert = getModal().errorAlert
      expect(alert).to.be.ok()
      expect(alert.props.liveRegion).to.be.ok()
      expect(testbed.getText(alert)).to.include('Error')
    })

    it('clears the files selected for upload on continue', () => {
      testbed.render({uploadStatus: FILE_UPLOAD_ERROR})
      testbed.click(getModal().confirmButton)
      expect(defaultProps.clearFiles.called).to.be.true()
    })

    it('sets the file upload status to FILE_UPLOAD_SELECT', () => {
      testbed.render({uploadStatus: FILE_UPLOAD_ERROR})
      testbed.click(getModal().confirmButton)
      expect(defaultProps.setUploadStatus.calledWith(FILE_UPLOAD_SELECT)).to.be.true()
    })

    sharedCancelDisabledExample(FILE_UPLOAD_ERROR)
    sharedContinueButtonExample({
      uploadStatus: FILE_UPLOAD_ERROR,
      files: defaultProps.files,
      disabled: false,
      buttonText: 'Start Over'
    })

    it('clears the files and sets the file upload status to select', () => {
      testbed.render({uploadStatus: FILE_UPLOAD_ERROR})
      testbed.click(getModal().confirmButton)
      expect(defaultProps.clearFiles.called).to.be.true()
      expect(defaultProps.setUploadStatus.calledWith(FILE_UPLOAD_SELECT)).to.be.true()
    })
  })

  const sharedContinueCloseModalExample = ({uploadStatus = FILE_UPLOAD_FAILURE} = {}) => {
    it('clears the files and closes the modal', () => {
      testbed.render({uploadStatus})
      testbed.click(getModal().confirmButton)
      expect(defaultProps.clearFiles.called).to.be.true()
      expect(defaultProps.closeModal.called).to.be.true()
    })
  }

  context('the import fails', () => {
    it('renders the import failed message', () => {
      testbed.render({uploadStatus: FILE_UPLOAD_FAILURE})
      const alert = getModal().failureAlert
      expect(alert).to.be.ok()
      expect(alert.props.liveRegion).to.be.ok()
      expect(testbed.getText(alert)).to.include('Error Details')
    })

    sharedCancelDisabledExample(FILE_UPLOAD_FAILURE)
    sharedContinueButtonExample({
      uploadStatus: FILE_UPLOAD_FAILURE,
      files: defaultProps.files,
      disabled: false,
      buttonText: 'Okay'
    })
    sharedContinueCloseModalExample()
  })

  context('the import is a success', () => {
    it('renders the success alert', () => {
      testbed.render({uploadStatus: FILE_UPLOAD_SUCCESS})
      const alert = getModal().successAlert
      expect(alert).to.be.ok()
      expect(alert.props.liveRegion).to.be.ok()
      expect(testbed.getText(alert)).to.include('Success')
    })

    sharedCancelDisabledExample(FILE_UPLOAD_SUCCESS)
    sharedContinueButtonExample({
      uploadStatus: FILE_UPLOAD_SUCCESS,
      files: defaultProps.files,
      disabled: false,
      buttonText: 'Done'
    })
    sharedContinueCloseModalExample(FILE_UPLOAD_SUCCESS)
  })

  describe('a11y tests', () => {
    it('should meet a11y standards', (done) => {
      testbed.render()
      testbed.checkA11yStandards(done)
    })
  })
})
