import React from 'react'
import { List } from 'immutable'
import Avatar from '@instructure/ui-elements/lib/components/Avatar'
import {
  expect,
  mount,
  within,
  stub,
  findWithLabel,
  wait} from '@instructure/ui-test-utils'

import QuizSession from '../../../../../common/records/QuizSession'
import QuizSessionResult from '../../../../../common/records/QuizSessionResult'
import ModerateTableRow from '../presenter'

describe('ModerateTableRow presenter', () => {
  const sandbox = sinon.createSandbox()

  stubComponent(Avatar)

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

  const quizSession = new QuizSession({ id: '1' })
  const props = {
    onModerateButtonClick () {},
    onModerateLogClick () {},
    quizSessions: List.of(quizSession),
    rowData: { avatar: 'zomgModerateTableRowPresenter', id: '42', name: 'lolwut', quizSessionIds: ['1'] }
  }

  const testbed = createTestbed(ModerateTableRow, props)
  const connectedTestbed = createTestbed(withContext(ModerateTableRow), props)
  shouldRenderComponent(connectedTestbed, {}, ModerateTableRow)

  describe('Accommodations column', () => {
    it('renders "None" when there is no accommodation data', async () => {
      const subject = await mount(
        <ModerateTableRow
          {...props}
          onAccommodationsClick={Function.prototype}
        />
      )
      const row = within(subject.getDOMNode())
      expect(await row.find(':textContent(None)')).to.exist()
    })

    it('renders the name of accommodations that are present', async () => {
      const accRow = {
        ...props.rowData,
        accommodations: [
          {displayString: 'attempts'},
          {displayString: 'time'}
        ]
      }
      const subject = await mount(
        <ModerateTableRow
          onAccommodationsClick={Function.prototype}
          onModerateButtonClick={props.onModerateButtonClick}
          onModerateLogClick={props.onModerateLogClick}
          quizSessions={props.quizSessions}
          rowData={accRow}
        />
      )
      const row = within(subject.getDOMNode())
      expect(await row.find(':textContent(attempts)')).to.exist()
      expect(await row.find(':textContent(time)')).to.exist()
    })

    it('does not render accommodations column if the cb is not present', async () => {
      const subject = await mount(
        <ModerateTableRow
          {...props}
        />
      )
      const row = within(subject.getDOMNode())
      expect(await row.find(':textContent(+ add)', {expectEmpty: true})).not.to.exist()
    })

    it('calls the accommodations cb when accommodation button is clicked', async () => {
      const cb = stub()
      await mount(
        <ModerateTableRow
          {...props}
          onAccommodationsClick={cb}
        />
      )
      const link = await findWithLabel('Edit student accommodations')
      await link.click()
      await wait(() => {
        expect(cb).to.have.been.calledOnce()
      })
    })
  })

  it('renders a moderate button by default', () => {
    const wrapper = testbed.renderShallowly()
    expect(wrapper.find('Button').exists()).to.be.true()
  })

  it('does not render a moderate button when shouldRenderModerateButton is false', () => {
    const wrapper = testbed.renderShallowly({ shouldRenderModerateButton : false })
    expect(wrapper.find('Button').exists()).to.be.false()
  })

  it('invokes onModerateButtonClick when the moderate button is clicked', () => {
    const onModerateButtonClick = sandbox.spy()
    const wrapper = testbed.renderShallowly({ onModerateButtonClick })

    wrapper.find('Button').simulate('click')

    expect(onModerateButtonClick).to.have.been.calledOnce()
    expect(onModerateButtonClick.firstCall.args[0]).to.deep.equal(props.rowData)
  })

  it('invokes onModerateLogClick when the log link is clicked', () => {
    const onModerateLogClick = sandbox.spy()
    const wrapper = testbed.renderShallowly({ onModerateLogClick })
    const viewLoglink = wrapper.find('Link').last()

    viewLoglink.simulate('click')

    expect(onModerateLogClick).to.have.been.calledOnce()
    expect(onModerateLogClick).to.have.been.calledWithMatch({ id: '42', quizSessionId: '1' })
  })

  it('renders scores', () => {
    const quizSessionResult = new QuizSessionResult({ score: 1, pointsPossible: 2 })
    sandbox.stub(quizSession, 'findAuthoritativeResult').returns(quizSessionResult)
    connectedTestbed.render()
    const output = connectedTestbed.getText()
    expect(output).to.include('50%')
  })

  it('renders non applicable scores', () => {
    const quizSessionResult = new QuizSessionResult({ pointsPossible: 0 })
    sandbox.stub(quizSession, 'findAuthoritativeResult').returns(quizSessionResult)
    connectedTestbed.render()
    const output = connectedTestbed.getText()
    expect(output).to.include('N/A')
  })

  it('renders empty score message', () => {
    connectedTestbed.render({ quizSessions: List() })
    const output = connectedTestbed.getText()
    expect(output).to.include('No Score')
  })

  it('renders in progress score message', () => {
    sandbox.stub(quizSession, 'inProgress').returns(true)
    connectedTestbed.render()
    const output = connectedTestbed.getText()
    expect(output).to.include('In progress, score not available')
    expect(output).to.include('---')
  })

  it('renders attempts when present', () => {
    connectedTestbed.render()
    const output = connectedTestbed.getText()
    expect(output).to.include('Attempt 1 / 1')
  })

  it('renders attempt as link if session is graded', () => {
    sandbox.stub(quizSession, 'graded').returns(true)
    const onResultsLinkClick = sandbox.spy()
    const wrapper = testbed.renderShallowly({ onResultsLinkClick })
    // We have one other rendering for the Log no matter what
    expect(wrapper.find('Link').length).to.equal(2)
  })

  it('does not render attempt as link if session is not graded', () => {
    sandbox.stub(quizSession, 'graded').returns(false)
    const onResultsLinkClick = sandbox.spy()
    const wrapper = testbed.renderShallowly({ onResultsLinkClick })
    // We have one other rendering for the Log no matter what
    expect(wrapper.find('Link').length).to.equal(1)
  })

  it('renders total attempt count in attempt output if present', () => {
    const maxAttempts = 5
    connectedTestbed.render({
      rowData: {
        ...props.rowData,
        maxAttempts
      }
    })
    const output = connectedTestbed.getText()
    expect(output).to.include('Attempt 1 / 5')
  })

  it('ignores second part of attempt output if maxAttempts is Infinity', () => {
    const maxAttempts = Infinity
    connectedTestbed.render({
      rowData: {
        ...props.rowData,
        maxAttempts
      }
    })
    const output = connectedTestbed.getText()
    expect(output).to.include('Attempt 1')
  })

  it('invokes onResultsLinkClick when the attempt result link is clicked', () => {
    sandbox.stub(quizSession, 'graded').returns(true)
    const onResultsLinkClick = sandbox.spy()
    const wrapper = testbed.renderShallowly({ onResultsLinkClick })
    const attemptLink = wrapper.find('Link').first()

    attemptLink.simulate('click')

    expect(onResultsLinkClick).to.have.been.calledOnce()
    expect(onResultsLinkClick).to.have.been.calledWithMatch('1')
  })

  it('renders empty attempt message', () => {
    connectedTestbed.render({ quizSessions: List() })
    const output = connectedTestbed.getText()
    expect(output).to.include('No Attempt')
  })

  it('renders empty time message', () => {
    connectedTestbed.render({ quizSessions: List() })
    const output = connectedTestbed.getText()
    expect(output).to.include('No Time')
  })

  it('renders in progress time message', () => {
    sandbox.stub(quizSession, 'inProgress').returns(true)
    connectedTestbed.render()
    const output = connectedTestbed.getText()
    expect(output).to.include('In progress, time not available')
    expect(output).to.include('---')
  })

  it('renders empty log message', () => {
    connectedTestbed.render({ quizSessions: List() })
    const output = connectedTestbed.getText()
    expect(output).to.include('No Log')
  })

  it('renders view log message', () => {
    sandbox.stub(quizSession, 'inProgress').returns(false)
    connectedTestbed.render()
    const output = connectedTestbed.getText()
    expect(output).to.include('View Log')
  })

  it('renders in progress log message', () => {
    sandbox.stub(quizSession, 'inProgress').returns(true)
    connectedTestbed.render()
    const output = connectedTestbed.getText()
    expect(output).to.include('In Progress')
  })
})
