import BreadcrumbLink from '@instructure/ui-breadcrumb/lib/components/Breadcrumb/BreadcrumbLink'
import Button from '@instructure/ui-buttons/lib/components/Button'

import * as immutable from 'immutable'

import Bank from '../presenter'
import PaginatedCollection from '../../../../common/components/shared/PaginatedCollection'
import BankRecord from '../../../../common/records/Bank'
import HeaderMenu from '../../../../banks/components/HeaderMenu'
import Page from '../../../../common/components/layout/Page'
import NavWrapper from '../../NavWrapper'
import BankSearch from '../../../../banks/components/BankSearch'

describe('Bank', () => {
  const bank = new BankRecord({
    id: 1,
    title: 'Units of Measurement'
  })

  const stubs = {
    addEntryToQuiz: sinon.stub().resolves(),
    getBankEntries: sinon.stub(),
    openModal: sinon.stub(),
    screenreaderNotification: sinon.stub()
  }
  const props = {
    ...stubs,
    bank,
    bankId: bank.id.toString(),
    getBank: Function.prototype,
    navigateToBankEntry: Function.prototype,
    navigateToBanks: Function.prototype,
    resetSearch: Function.prototype,
    search: immutable.fromJS({ interactionTypes: immutable.Set() }),
  }
  const testbed = createTestbed(Bank, props)
  const connectedTestbed = createTestbed(withContext(Bank), props)

  afterEach(() => {
    Object.keys(stubs).forEach((key) => stubs[key].resetHistory())
  })

  it('renders a Page component', () => {
    const output = testbed.renderShallowly()
    expect(output.find(Page)).to.have.length(1)
  })

  it('renders Bank app navigation', () => {
    const output = testbed.renderShallowly()
    const crumbs = output.find(BreadcrumbLink)
    expect(crumbs.length).to.eq(1)
  })

  it('fetches bank entries', (done) => {
    connectedTestbed.mount()
    setTimeout(() => {
      expect(stubs.getBankEntries).to.have.been.calledWithMatch(1, false, { page: 1 })
      done()
    }, 100)
  })

  it('does not render a return-to-build button when not passed a navigateToBuild prop', () => {
    const output = testbed.renderShallowly({ navigateToBuild: null })
    const buttons = output.find(Button)
    const texts = buttons.map(button => buttons.first().prop('children'))
    expect(texts.join()).to.not.include('Return')
  })

  it('passes the rendereHeaderMenu function to the NavWrapper', () => {
    const output = testbed.renderShallowly()
    const navWrapper = output.find(NavWrapper)
    expect(navWrapper.prop('renderHeaderMenu')).to.not.be.undefined()
  })

  it('does not render Bank header menu in compact mode', () => {
    const output = testbed.renderShallowly({ isCompact: true })
    expect(output.find(HeaderMenu).length).to.eq(0)
  })

  it('does render addBankToQuiz button if not empty', () => {
    const output = testbed.renderShallowly({
      isCompact: true,
      bank: {itemEntryCount: 1}
    })
    const buttons = output.find(Button)
    expect(buttons.length).to.equal(1)
    const buttonText = buttons.render().text()
    expect(buttonText).to.include('All / Random')
  })

  it('does not render addBankToQuiz button if empty', () => {
    const output = testbed.renderShallowly({
      isCompact: true,
      bank: {itemEntryCount: 0}
    })
    const buttons = output.find(Button)
    expect(buttons.length).to.equal(0)
  })

  it('cascades addEntryToQuiz iff compact mode', () => {
    const output = testbed.renderShallowly()
    const collection = output.find(PaginatedCollection).first()
    const bankEntriesList = collection.prop('renderRecords')()
    expect(bankEntriesList.props.addEntryToQuiz).to.be.null()

    const compact = testbed.renderShallowly({ isCompact: true })
    const compactCollection = compact.find(PaginatedCollection).first()
    const compactList = compactCollection.prop('renderRecords')()
    expect(compactList.props.addEntryToQuiz).to.equal(stubs.addEntryToQuiz)
  })

  it('opens addBankEntryModal', () => {
    const output = testbed.renderShallowly()
    const newEntryButton = output.find(Button).first()
    newEntryButton.simulate('click')
    expect(stubs.openModal).to.have.been.called()
  })

  describe('addBankToQuiz', () => {
    it('calls addEntryToQuiz and alerts the screenreader', (done) => {
      const output = testbed.renderShallowly({
        isCompact: true,
        bank: {itemEntryCount: 1}
      })
      const addBankToQuizButton = output.find(Button).first()
      addBankToQuizButton.simulate('click')
      expect(stubs.addEntryToQuiz).to.have.been.called()
      setTimeout(() => {
        expect(stubs.screenreaderNotification).to.have.been.called()
        done()
      })
    })
  })

  it('renders search bar if filters are present', () => {
    const output = testbed.renderShallowly({
      bank: { filters: { some: 'filters' } },
      useBankSearch: true
    })
    const search = output.find(BankSearch)
    expect(search.length).to.equal(1)
  })

  it('does not render search bar when filters are not present', () => {
    const output = testbed.renderShallowly({
      bank: { filters: null }
    })
    const search = output.find(BankSearch)
    expect(search.length).to.equal(0)
  })

  it('notifies the user via screen reader when search results change', async () => {
    const output = testbed.renderShallowly({
      ...props,
      getBankEntries: () => Promise.resolve({ totalPages: 1 })
    })

    const bank = output.instance()
    bank.debouncedAnnounceResults = bank.announceResults
    bank.getPage(1, immutable.fromJS({}))
    await new Promise((r) => setTimeout(r, 0))
    expect(stubs.screenreaderNotification).to.have.been.calledWith('Displaying one page of results')
  })

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