import React from 'react'

import { List } from 'immutable'

import Button from '@instructure/ui-buttons/lib/components/Button'
import IconMoveLeftLine from '@instructure/ui-icons/lib/Line/IconMoveLeft'
import IconMoveRightLine from '@instructure/ui-icons/lib/Line/IconMoveRight'

import Pin from '../Pin'
import Sidebar from '../index'
import styles from '../styles.css'

describe('Common Sidebar Presenter', () => {
  const scrollToItemStub = sinon.stub()
  const toggleSidebarStub = sinon.stub()

  const props = {
    children: [<div key="1">child1</div>, <div key="2">child2</div>],
    scrollToItem: () => scrollToItemStub,
    sidebarOpen: true,
    screenreaderNotification: sinon.stub(),
    toggleSidebar: toggleSidebarStub,
    pinnedItems: List([{ sessionItemId: '11', position: 1 }])
  }

  afterEach(() => {
    scrollToItemStub.resetHistory()
    toggleSidebarStub.resetHistory()
  })

  const testbed = createTestbed(Sidebar, props)

  shouldRenderComponent(testbed, {}, Sidebar)

  it('displays children', () => {
    testbed.render()
    const text = testbed.getText()
    expect(text).to.contain('child1')
    expect(text).to.contain('child2')
  })

  it('passes the role prop to the wrapper div', () => {
    const role = 'complementary'
    testbed.render({ role })
    expect(
      testbed.findChildrenByTagNameAndAttribute('div', 'role', role)
    ).to.have.length(1)
  })

  describe('sidebar is open', () => {
    it('should append a sidebarIsOpen class', () => {
      testbed.render({sidebarOpen: true})
      const nodeWithIsOpenClass = testbed.findChildrenByClass(styles.sidebarIsOpen)[0]
      expect(nodeWithIsOpenClass).to.not.be.undefined()
    })
  })

  describe('sidebar is closed', () => {
    it('should not have a sidebarIsOpen class', () => {
      testbed.render({sidebarOpen: false})
      const nodeWithIsOpenClass = testbed.findChildrenByClass(styles.sidebarIsOpen)[0]
      expect(nodeWithIsOpenClass).to.be.undefined()
    })
  })

  describe('#scrollToTitle', () => {
    it('calls the sidebarActions#scrollToItem with title', () => {
      testbed.render()
      const subject = testbed.findChildByType(Sidebar)
      subject.scrollToTitle()
      expect(scrollToItemStub.getCall(0).args[0]).to.eq('title')
    })
  })

  describe('#scrollToInfo', () => {
    it('calls the sidebarActions#scrollToItem with info', () => {
      testbed.render()
      const subject = testbed.findChildByType(Sidebar)
      subject.scrollToInfo()
      expect(scrollToItemStub.getCall(0).args[0]).to.eq('instructions')
    })
  })

  describe('sidebar handleBlur', () => {
    it('should close the sidebar on mobile', (done) => {
      testbed.render({ sidebarOpen: true })
      const sidebar = testbed.findChildByType(Sidebar)
      sinon.stub(sidebar, 'onPhone').returns(true)
      sidebar.handleBlur()

      setTimeout(() => {
        expect(toggleSidebarStub).to.have.been.called()
        done()
      })
    })

    it('should keep the sidebar open when not on mobile', (done) => {
      testbed.render({ sidebarOpen: true })
      const sidebar = testbed.findChildByType(Sidebar)
      sinon.stub(sidebar, 'onPhone').returns(false)
      sidebar.handleBlur()

      setTimeout(() => {
        expect(toggleSidebarStub).to.have.not.been.called()
        done()
      })
    })

    it('should not toggle the sidebar if the sidebar was closed', (done) => {
      testbed.render({ sidebarOpen: false })
      const sidebar = testbed.findChildByType(Sidebar)
      sinon.stub(sidebar, 'onPhone').returns(true)
      sidebar.handleBlur()

      setTimeout(() => {
        expect(toggleSidebarStub).to.have.not.been.called()
        done()
      })
    })
  })

  describe('sidebar handleTransitionEnd', () => {
    it('fires a window resize event on transition end', () => {
      testbed.render()
      const resizeStub = sinon.stub()
      window.onresize = resizeStub
      const sidebar = testbed.findChildByType(Sidebar)
      sidebar.handleTransitionEnd()
      expect(resizeStub).to.have.been.called()
    })
  })

  describe('header', () => {
    context('open', () => {
      it('shows \'Question Navigator\' text', () => {
        testbed.render()
        const text = testbed.getText()
        expect(text).to.include('Question Navigator')
      })

      it('renders the IconMoveLeftLine icon', () => {
        testbed.render()
        const icon = testbed.findChildrenByType(IconMoveLeftLine)[0]
        expect(icon).to.not.be.undefined()
      })

      it('renders the correct button text', () => {
        testbed.render()
        const text = testbed.getText()
        expect(text).to.include('Close Menu')
      })
    })

    context('closed', () => {
      it('hides \'Question Navigator\' text', () => {
        testbed.render({sidebarOpen: false})
        const navDiv = testbed.findChildrenByClass(styles.sidebarClosed)[0]
        expect(navDiv.innerText).to.include('Question Navigator')
      })

      it('renders the IconMoveRightLine icon', () => {
        testbed.render({sidebarOpen: false})
        const icon = testbed.findChildrenByType(IconMoveRightLine)[0]
        expect(icon).to.not.be.undefined()
      })

      it('renders the correct button text', () => {
        testbed.render({sidebarOpen: false})
        const text = testbed.getText()
        expect(text).to.include('Open Menu')
      })
    })

    it('calls toggle sidebar when menu button clicked', () => {
      testbed.render()
      const btn = testbed.findChildrenByType(Button)[0]
      testbed.click(btn)
      expect(toggleSidebarStub).to.have.been.called()
    })
  })

  describe('title', () => {
    it('renders the string \'Title\' if no prop is given', () => {
      testbed.render()
      const text = testbed.getText()
      expect(text).to.include('Title')
    })

    it('shows the title prop if given', () => {
      testbed.render({title: 'hola'})
      const text = testbed.getText()
      expect(text).to.include('hola')
      expect(text).not.to.include('Title')
    })
  })

  describe('shows instructions', () => {
    it("Renders 'Instructions' in sidebar", () => {
      testbed.render({taking: true})
      const instructions = testbed.findChildrenByClass(styles.description)[1]
      expect(instructions.innerText).to.eql('Instructions')
    })

    it('shows instructions by default', () => {
      testbed.render()
      const descriptionElements = testbed.findChildrenByClass(styles.description)
      expect(descriptionElements.length).to.equal(2)
    })
  })

  describe('pinned section', () => {
    context('taking is true', () => {
      it('renders the title of the section', () => {
        testbed.render({ taking: true })
        expect(testbed.getText()).to.include('Pinned Questions')
      })

      it('renders the proper number of pins', () => {
        testbed.render({ taking: true })
        expect(testbed.findChildrenByType(Pin).length).to.eq(1)
      })

      it('calls the scrollToItem stub when clicked', () => {
        testbed.render({ taking: true })
        const pin = testbed.findChildByType(Pin)
        testbed.click(pin)
        expect(scrollToItemStub).to.be.calledWith('11')
      })
    })

    context('taking is not true', () => {
      it('does not render the title of the section', () => {
        testbed.render()
        expect(testbed.getText()).to.not.include('Pinned Questions')
      })
    })
  })

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