import React from 'react'

import Button from '@instructure/ui-buttons/lib/components/Button'
import { mount, find, findAll, stub } from '@instructure/ui-test-utils'

import LearnosityCalculator from '../index'

describe('LearnosityCalculator', () => {
  const render = ({ toggleCalculator, enabled }) => (
    <Button onClick={toggleCalculator} disabled={!enabled}>Hello</Button>
  )
  const props = {
    activeCalculatorId: null,
    appendFeature: Function.prototype,
    calculatorType: 'none',
    destroyFeature: Function.prototype,
    featureId: `calc_${new Date().getTime()}`,
    quizSessionId: '42',
    render,
    setActiveCalculatorId: Function.prototype,
    toggleFeature: Function.prototype
  }

  it('does not add content from render prop when type is none', async () => {
    await mount(<LearnosityCalculator {...props} />)
    expect(await findAll('button', { expectEmpty: true })).to.have.length(0)
  })

  it('adds content from render prop when type is basic', async () => {
    await mount(<LearnosityCalculator {...props} calculatorType="basic" />)
    expect(await findAll('button')).to.have.length(1)
  })

  it('appends the calculator', async () => {
    const appendFeature = stub()
    await mount(
      <LearnosityCalculator
        {...props}
        appendFeature={appendFeature}
        calculatorType="basic"
      />
    )
    const feature = {
      type: 'calculator',
      mode: 'basic',
      feature_id: props.featureId
    }
    expect(appendFeature).to.have.been.calledOnce()
    expect(appendFeature).to.have.been.calledWithMatch(props.quizSessionId, feature)
  })

  it('sets its own feature id if none is provided', async () => {
    const appendFeature = stub()
    await mount(
      <LearnosityCalculator
        {...props}
        appendFeature={appendFeature}
        calculatorType="basic"
        featureId={null}
      />
    )
    expect(appendFeature).to.have.been.calledOnce()
    expect(appendFeature.firstCall.args[1].feature_id).to.be.a('string')
  })

  it('destroys the calculator when component is unmounted', async () => {
    const destroyFeature = stub()
    await mount(
      <LearnosityCalculator
        {...props}
        calculatorType="basic"
        destroyFeature={destroyFeature}
      />
    )
    // TODO: use `unmount` when https://gerrit.instructure.com/186391 lands
    await mount(<div />)
    expect(await findAll('.learnosity-feature', { expectEmpty: true })).to.have.length(0)
    expect(destroyFeature).to.have.been.calledOnceWith(props.featureId)
  })

  it('updates component when the type is changed', async () => {
    await mount(<LearnosityCalculator {...props} />)
    expect(await findAll('button', { expectEmpty: true })).to.have.length(0)

    await mount(<LearnosityCalculator {...props} calculatorType="scientific" />)
    expect(await findAll('button')).to.have.length(1)

    await mount(<LearnosityCalculator {...props} />)
    expect(await findAll('button', { expectEmpty: true })).to.have.length(0)
  })

  it('passes disabled before learnosity authenticated', async () => {
    const appendFeature = () => new Promise()
    await mount(
      <LearnosityCalculator
        {...props}
        appendFeature={appendFeature}
        calculatorType="basic"
      />
    )
    const button = await find('button')
    expect(button.getDOMNode().disabled).to.be.true()
  })

  it('passes enabled when learnosity authenticated', async () => {
    await mount(<LearnosityCalculator {...props} calculatorType="basic" />)
    const button = await find('button')
    expect(button.getDOMNode().disabled).to.be.false()
  })

  it('passes function to toggle calculator', async () => {
    const toggleFeature = stub()
    await mount(
      <LearnosityCalculator
        {...props}
        calculatorType="basic"
        toggleFeature={toggleFeature}
      />
    )
    const button = await find('button')
    await button.click()
    expect(toggleFeature).to.have.been.calledOnceWith(props.featureId)
  })

  it('sets active calculator id when activated', async () => {
    const setActiveCalculatorId = stub()
    await mount(
      <LearnosityCalculator
        {...props}
        calculatorType="basic"
        setActiveCalculatorId={setActiveCalculatorId}
      />
    )
    const button = await find('button')
    await button.click()
    expect(setActiveCalculatorId).to.have.been.calledOnceWith(props.featureId)
  })

  it('toggles calculator off when active calculator id changes', async () => {
    const toggleFeature = stub()
    const subject = await mount(
      <LearnosityCalculator
        {...props}
        calculatorType="basic"
        toggleFeature={toggleFeature}
      />
    )
    await subject.setProps({ activeCalculatorId: 'abc' })
    expect(toggleFeature).to.have.been.calledOnceWith(props.featureId, false)
  })

  it('does not toggle calculator off when active calculator id changes to self', async () => {
    const toggleFeature = stub()
    const subject = await mount(
      <LearnosityCalculator
        {...props}
        calculatorType="basic"
        toggleFeature={toggleFeature}
      />
    )
    await subject.setProps({ activeCalculatorId: props.featureId })
    expect(toggleFeature).not.to.have.been.called()
  })

  context('when no quiz session id is given', () => {
    it('does not render anything', async () => {
      const subject = await mount(
        <LearnosityCalculator
          {...props}
          calculatorType="basic"
          quizSessionId={null}
        />
      )
      expect(subject.getDOMNode()).not.to.exist()
    })

    it('appends the calculator if a quiz session id is subsequently provided', async () => {
      const appendFeature = stub()
      const subject = await mount(
        <LearnosityCalculator
          {...props}
          appendFeature={appendFeature}
          calculatorType="basic"
          quizSessionId={null}
        />
      )
      await subject.setProps({ quizSessionId: props.quizSessionId })
      expect(appendFeature).to.have.been.calledOnce()
    })
  })
})
