import ExtraHoursMinutes from '../index'
import ReactTestUtils from 'react-dom/test-utils'

describe('ExtraHoursMinutes', () => {
  const sandbox = sinon.createSandbox()
  const onChangeStub = sandbox.stub()

  const defaultProps = {
    onChange: onChangeStub,
    extraTimeInSeconds: 480,
    maxTimeInSeconds: 72000,
  }

  const testbed = createTestbed(ExtraHoursMinutes, defaultProps)

  const getInputByLabelText = (testbed, labelText) => {
    const labels = testbed.findChildrenByTagName('label')
    const label = labels.filter(el => {
      return testbed.getText(el).indexOf(labelText) > -1
    })

    return label[0].querySelector ? label[0].querySelector('input') : null
  }

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

  it('renders hour and minute inputs', () => {
    testbed.render()
    expect(getInputByLabelText(testbed, 'Hours')).to.exist()
    expect(getInputByLabelText(testbed, 'Minutes')).to.exist()
  })

  it('should accept input of minutes', () => {
    testbed.render()
    const input = getInputByLabelText(testbed, 'Minutes')
    testbed.change(input, '17')
    ReactTestUtils.Simulate.blur(input)
    expect(input.value).to.equal('17')
  })

  it('should accept input of hours', () => {
    testbed.render()
    const input = getInputByLabelText(testbed, 'Hours')
    testbed.change(input, '2')
    ReactTestUtils.Simulate.blur(input)
    expect(input.value).to.equal('2')
  })

  it('should accept minutes and callback correct number of seconds', () => {
    testbed.render()
    const input = getInputByLabelText(testbed, 'Minutes')
    testbed.change(input, '27')
    ReactTestUtils.Simulate.blur(input)
    expect(onChangeStub).to.have.been.calledWith(27 * 60)
  })

  it('should accept hours and callback correct number of seconds', () => {
    testbed.render()
    const minutesInput = getInputByLabelText(testbed, 'Minutes')
    const hoursInput = getInputByLabelText(testbed, 'Hours')
    testbed.change(minutesInput, '0')
    testbed.change(hoursInput, '3')
    ReactTestUtils.Simulate.blur(minutesInput)
    ReactTestUtils.Simulate.blur(hoursInput)
    expect(onChangeStub).to.have.been.calledWith(3 * 60 * 60)
  })

  it('should convert minutes to hours when 60 or greater', () => {
    testbed.render()
    const minutesInput = getInputByLabelText(testbed, 'Minutes')
    const hoursInput = getInputByLabelText(testbed, 'Hours')
    testbed.change(minutesInput, '159')
    ReactTestUtils.Simulate.blur(minutesInput)
    expect(hoursInput.value).to.equal('2')
    expect(minutesInput.value).to.equal('39')
  })

  it('should callback a maximum of maxTimeInSeconds', () => {
    testbed.render()
    const hoursInput = getInputByLabelText(testbed, 'Hours')
    testbed.change(hoursInput, defaultProps.maxTimeInSeconds * 2)
    ReactTestUtils.Simulate.blur(hoursInput)
    const minutesInput = getInputByLabelText(testbed, 'Minutes')
    testbed.change(minutesInput, defaultProps.maxTimeInSeconds * 2)
    ReactTestUtils.Simulate.blur(minutesInput)
    expect(onChangeStub).to.have.been.calledWith(defaultProps.maxTimeInSeconds)
  })

  it('should reset hour and minute inputs to max if needed on blur', () => {
    testbed.render({...defaultProps, maxTimeInSeconds: 5700})
    const hoursInput = getInputByLabelText(testbed, 'Hours')
    const minutesInput = getInputByLabelText(testbed, 'Minutes')
    testbed.change(minutesInput, 9999)
    testbed.change(hoursInput, 9999)
    ReactTestUtils.Simulate.blur(hoursInput)
    expect(hoursInput.value).to.equal('1')
    expect(minutesInput.value).to.equal('35')
  })

  it('should callback a minimum of 0', () => {
    testbed.render()
    const minutesInput = getInputByLabelText(testbed, 'Minutes')
    const hoursInput = getInputByLabelText(testbed, 'Hours')
    testbed.change(hoursInput, -5)
    ReactTestUtils.Simulate.blur(hoursInput)
    testbed.change(minutesInput, -17)
    ReactTestUtils.Simulate.blur(minutesInput)
    expect(onChangeStub).to.have.been.calledWith(0)
  })

  it('should ignore a non-number input of minutes', () => {
    testbed.render()
    const input = getInputByLabelText(testbed, 'Minutes')
    testbed.change(input, 'apple')
    ReactTestUtils.Simulate.blur(input)
    expect(onChangeStub).to.have.been.calledWith(defaultProps.extraTimeInSeconds)
  })

  it('should ignore a non-number input of hours', () => {
    testbed.render()
    const input = getInputByLabelText(testbed, 'Hours')
    testbed.change(input, '12banana5')
    ReactTestUtils.Simulate.blur(input)
    expect(onChangeStub).to.have.been.calledWith(defaultProps.extraTimeInSeconds)
  })

  it('should pass error message to child on invalid minutes input', () => {
    testbed.render()
    const input = getInputByLabelText(testbed, 'Minutes')
    testbed.change(input, 'apple')
    expect(testbed.getText()).to.include('apple is not a valid number')
  })

  it('should pass error message to child on invalid hours input', () => {
    testbed.render()
    const input = getInputByLabelText(testbed, 'Hours')
    testbed.change(input, 'ki23wi')
    expect(testbed.getText()).to.include('ki23wi is not a valid number')
  })

  it('should pass error message to child on invalid minutes input with blur', () => {
    testbed.render()
    const input = getInputByLabelText(testbed, 'Minutes')
    testbed.change(input, 'apple')
    ReactTestUtils.Simulate.blur(input)
    expect(testbed.getText()).to.include('apple is not a valid number')
  })

  it('should pass error message to child on invalid hours input with blur', () => {
    testbed.render()
    const input = getInputByLabelText(testbed, 'Hours')
    testbed.change(input, 'ki23wi')
    ReactTestUtils.Simulate.blur(input)
    expect(testbed.getText()).to.include('ki23wi is not a valid number')
  })

  it('should not pass error message to child on valid minutes input', () => {
    testbed.render()
    const input = getInputByLabelText(testbed, 'Minutes')
    testbed.change(input, 'pear')
    testbed.change(input, '7')
    expect(testbed.getText()).not.to.include('is not a valid number')
  })

  it('should not pass error message to child on valid hours input', () => {
    testbed.render()
    const input = getInputByLabelText(testbed, 'Hours')
    testbed.change(input, 'pear')
    testbed.change(input, '7')
    expect(testbed.getText()).not.to.include('is not a valid number')
  })

  it('should reset invalid hours to last good value on blur', () => {
    testbed.render()
    const input = getInputByLabelText(testbed, 'Hours')
    testbed.change(input, '3')
    testbed.change(input, 'pear')
    ReactTestUtils.Simulate.blur(input)
    expect(input.value).to.equal('3')
  })

  it('should reset invalid minutes to last good value on blur', () => {
    testbed.render()
    const input = getInputByLabelText(testbed, 'Minutes')
    testbed.change(input, '52')
    testbed.change(input, 'kiwi')
    ReactTestUtils.Simulate.blur(input)
    expect(input.value).to.equal('52')
  })

  it('should increment correctly on keyboard arrow input', () => {
    testbed.render()
    const hoursInput = getInputByLabelText(testbed, 'Hours')
    const minutesInput = getInputByLabelText(testbed, 'Minutes')
    testbed.change(minutesInput, '59')
    testbed.change(hoursInput, '1')

    ReactTestUtils.Simulate.keyDown(minutesInput, { key: 'ArrowUp', keyCode: 38 })
    expect(minutesInput.value).to.equal('0')
    expect(hoursInput.value).to.equal('2')
    expect(onChangeStub).to.have.been.calledWith(7200)
  })

  it('should decrement correctly on keyboard arrow input', () => {
    testbed.render()
    const hoursInput = getInputByLabelText(testbed, 'Hours')
    const minutesInput = getInputByLabelText(testbed, 'Minutes')
    testbed.change(minutesInput, '0')
    testbed.change(hoursInput, '4')

    ReactTestUtils.Simulate.keyDown(minutesInput, { key: 'ArrowDown', keyCode: 40 })
    expect(minutesInput.value).to.equal('59')
    expect(hoursInput.value).to.equal('3')
    expect(onChangeStub).to.have.been.calledWith(14340)
  })

  it('should normalize correctly on increment', () => {
    testbed.render()
    const hoursInput = getInputByLabelText(testbed, 'Hours')
    const minutesInput = getInputByLabelText(testbed, 'Minutes')
    testbed.change(minutesInput, '65')
    testbed.change(hoursInput, '1')

    ReactTestUtils.Simulate.keyDown(minutesInput, { key: 'ArrowUp', keyCode: 38 })
    expect(minutesInput.value).to.equal('6')
    expect(hoursInput.value).to.equal('2')
    expect(onChangeStub).to.have.been.calledWith(7560)
  })

  it('should normalize correctly on decrement', () => {
    testbed.render()
    const hoursInput = getInputByLabelText(testbed, 'Hours')
    const minutesInput = getInputByLabelText(testbed, 'Minutes')
    testbed.change(minutesInput, '65')
    testbed.change(hoursInput, '1')

    ReactTestUtils.Simulate.keyDown(minutesInput, { key: 'ArrowDown', keyCode: 40 })
    expect(minutesInput.value).to.equal('4')
    expect(hoursInput.value).to.equal('2')
    expect(onChangeStub).to.have.been.calledWith(7440)
  })

  it('should be accessible', (done) => {
    testbed.render()
    testbed.checkA11yStandards(done)
  })

})
