import { List, Map } from 'immutable'
import SharingModal from '../presenter'

import {
  CAN_EDIT
} from '@instructure/quiz-common/lib/constants'

describe('SharingModal', () => {
  const onDismiss = sinon.stub()
  const onSubmit = sinon.stub()
  const getUserInfoStub = sinon.stub()
  const sharedBankStub = sinon.stub()
  const getSharedBanksStub = sinon.stub()
  const removeSharedBankStub = sinon.stub()
  const getBankStub = sinon.stub()

  const search = () => {
    return {then: (fn) => fn([{
      uuid: '0',
      fullName: 'first fullName',
      avatar: 'http://avatars.com/avatar0'
    }, {
      uuid: '1',
      fullName: 'second fullName',
      avatar: 'http://avatars.com/avatar1'
    }, {
      uuid: '2',
      fullName: 'third fullName',
      avatar: 'http://avatars.com/avatar2'
    }, {
      uuid: '3',
      fullName: 'fourth fullName',
      avatar: 'http://avatars.com/avatar3'
    }])}
  }

  const props = {
    isOpen: true,
    bank: Map({ bankId: '1', title: 'This is a title' }),
    onDismiss,
    onSubmit,
    search,
    getUserInfo: getUserInfoStub,
    shareBank: sharedBankStub,
    getSharedBanks: getSharedBanksStub,
    removeSharedBank: removeSharedBankStub,
    getBank: getBankStub,

    searchSelection: [{
      uuid: '3',
      fullName: 'third fullName',
      avatar: 'http://avatars.com/avatar3',
      permission: CAN_EDIT
    }, {
      uuid: '4',
      fullName: 'forth fullName',
      avatar: 'http://avatars.com/avatar4',
      permission: CAN_EDIT
    }]
  }

  const testbed = createTestbed(withContext(SharingModal), props)

  afterEach(() => {
    onDismiss.resetHistory()
    onSubmit.resetHistory()
  })

  shouldRenderComponent(testbed, {}, SharingModal)

  describe('handleDismiss', () => {
    it('calls focus on the modalTrigger if passed', () => {
      const focusStub = sinon.stub()
      const subject = testbed.render({
        modalTrigger: { focus: focusStub }
      })
      subject.refs.composedComponent.handleDismiss()
      expect(focusStub).to.have.been.called()
    })

    it('removes the owner temp record', () => {
      const focusStub = sinon.stub()
      const subject = testbed.render({
        modalTrigger: { focus: focusStub }
      })
      subject.refs.composedComponent.handleDismiss()
      expect(removeSharedBankStub).to.have.been.calledWith('-1')
    })
  })

  describe('handleSubmit', () => {
    it('calls focus on the modalTrigger if passed', () => {
      const focusStub = sinon.stub()
      const subject = testbed.render({
        modalTrigger: { focus: focusStub }
      })
      subject.refs.composedComponent.handleSubmit()
      expect(focusStub).to.have.been.called()
    })

    it('should call getBank correctly', (done) => {
      const subject = testbed.render({
        bank: { id: '1', title: 'This is a title', sharedCount: 2 }
      })

      subject.refs.composedComponent.handleSearchSelectionChange([{
        uuid: '0',
        fullName: 'first fullName',
        avatar: 'http://avatars.com/avatar1'
      }])

      subject.refs.composedComponent.handleShare()
      subject.refs.composedComponent.handleSubmit()

      setTimeout(() => {
        expect(getBankStub).to.have.been.calledWith('1')
        done()
      })
    })

    it('should call removeSharedBank correctly', (done) => {
      const subject = testbed.render({
        bank: { id: '1', title: 'This is a title', sharedCount: 2 }
      })

      subject.refs.composedComponent.handleSearchSelectionChange([{
        uuid: '0',
        fullName: 'first fullName',
        avatar: 'http://avatars.com/avatar1'
      }])

      subject.refs.composedComponent.handleShare()
      subject.refs.composedComponent.handleSubmit()

      setTimeout(() => {
        expect(removeSharedBankStub).to.have.been.calledWith('-1')
        done()
      })
    })
  })

  it('should update search selection correctly', () => {
    const subject = testbed.render()

    subject.refs.composedComponent.handleSearchSelectionChange([1, 2, 3])
    expect(subject.refs.composedComponent.state.searchSelection).to.deep.equal([1, 2, 3])
  })

  it('should update newPeople correctly', () => {
    const subject = testbed.render({
      bank: { bankId: '1', title: 'This is a title'}
    })

    subject.refs.composedComponent.handleSearchSelectionChange([{
      uuid: '0',
      fullName: 'first fullName',
      avatar: 'http://avatars.com/avatar1'
    }])

    subject.refs.composedComponent.handleShare()

    expect(subject.refs.composedComponent.state.newPeople).to.deep.equal(
      List(
        [Map({
          id: '0',
          userUuid: '0',
          fullName: 'first fullName',
          avatar: 'http://avatars.com/avatar1',
          permission: CAN_EDIT
        })]
      )
    )
  })

  it('should call getSharedBanks with right parameters', () => {
    const bank = { id: '1', title: 'This is a title' }
    testbed.render({
      bank: bank
    })

    expect(getSharedBanksStub).to.have.been.calledWith(bank, getUserInfoStub)
  })

  it('should not call getSharedBanks when sharedBanks has data', () => {
    const getSharedBanksStub = sinon.stub()
    testbed.render({
      sharedBanks: List([
        Map({ id: '1', userUuid: '1', bankId: '1', permission: CAN_EDIT, full_name: 'firstFullName', avatar: 'http://avatars.com/avatar1' }),
        Map({ id: '2', userUuid: '2', bankId: '1', permission: CAN_EDIT, full_name: 'secondFullName', avatar: 'http://avatars.com/avatar2' })
      ])
    })

    expect(getSharedBanksStub).to.not.have.been.called()
  })

  describe('handleSearchFilter', () => {
    it('should filter out current user when sharedBanks has no data', () => {
      const subject = testbed.render({
        bank: { title: 'bank1', owner: '1', sharedCount: 0 }
      })

      const result = subject.refs.composedComponent.handleSearchFilter([{
        value: '1',
        fullName: 'first fullName',
        avatar: 'http://avatars.com/avatar1'
      }, {
        value: '2',
        fullName: 'second fullName',
        avatar: 'http://avatars.com/avatar2'
      }])

      expect(result).to.deep.equal([
        { value: '2', fullName: 'second fullName', avatar: 'http://avatars.com/avatar2' }
      ])
    })

    it('should NOT filter out current user when sharedBanks has data', () => {
      const subject = testbed.render({
        bank: { title: 'bank1', owner: '1', sharedCount: 2 }
      })

      const result = subject.refs.composedComponent.handleSearchFilter([{
        value: '0',
        fullName: 'first fullName',
        avatar: 'http://avatars.com/avatar0'
      }, {
        value: '1',
        fullName: 'second fullName',
        avatar: 'http://avatars.com/avatar1'
      }])

      expect(result).to.deep.equal([
        { value: '0', fullName: 'first fullName', avatar: 'http://avatars.com/avatar0' },
        { value: '1', fullName: 'second fullName', avatar: 'http://avatars.com/avatar1' }
      ])
    })

    it('should filter out people from autocomplete', () => {
      const subject = testbed.render({
        bank: { title: 'bank1', owner: '1', sharedCount: 2 },
        sharedBanks: List([
          Map({ id: '1', userUuid: '1', bankId: '1', permission: CAN_EDIT, full_name: 'first FullName', avatar: 'http://avatars.com/avatar1' }),
          Map({ id: '2', userUuid: '2', bankId: '1', permission: CAN_EDIT, full_name: 'second FullName', avatar: 'http://avatars.com/avatar2' })
        ])
      })

      const result = subject.refs.composedComponent.handleSearchFilter([{
        value: '2',
        fullName: 'second fullName',
        avatar: 'http://avatars.com/avatar2'
      }, {
        value: '3',
        fullName: 'third fullName',
        avatar: 'http://avatars.com/avatar3'
      }])

      expect(result).to.deep.equal([
        { value: '3', fullName: 'third fullName', avatar: 'http://avatars.com/avatar3' }
      ])
    })

    it('should populate peopleToRemove correctly', () => {
      const subject = testbed.render({
        sharedBanks: List([
          Map({ id: '1', userUuid: '1', bankId: '1', permission: CAN_EDIT, full_name: 'first FullName', avatar: 'http://avatars.com/avatar1' }),
          Map({ id: '2', userUuid: '2', bankId: '1', permission: CAN_EDIT, full_name: 'second FullName', avatar: 'http://avatars.com/avatar2' })
        ])
      })

      subject.refs.composedComponent.handlePersonRemove('2', false)

      expect(subject.refs.composedComponent.state.peopleToRemove).to.deep.equal(
        ['2']
      )
    })

    it('should remove people from peopleToRemove correctly', () => {
      const subject = testbed.render({
        bank: { title: 'bank1', owner: '1', sharedCount: 0 },
        sharedBanks: List([
          Map({ id: '1', userUuid: '1', bankId: '1', permission: CAN_EDIT, full_name: 'first FullName', avatar: 'http://avatars.com/avatar1' }),
          Map({ id: '2', userUuid: '2', bankId: '1', permission: CAN_EDIT, full_name: 'second FullName', avatar: 'http://avatars.com/avatar2' })
        ])
      })
      subject.refs.composedComponent.handlePersonRemove('1', false)
      subject.refs.composedComponent.handlePersonRemove('2', false)
      subject.refs.composedComponent.handlePersonRemove('1', true)

      expect(subject.refs.composedComponent.state.peopleToRemove).to.deep.equal(
        ['2']
      )
    })

    it('should render spinner if sharedBanks has not loaded yet', () => {
      testbed.render()
      expect(testbed.getText()).to.include('Loading...')
    })

    it('should NOT render spinner if sharedBanks has data', () => {
      testbed.render({
        bank: { title: 'bank1', owner: '1', sharedCount: 2 },
        sharedBanks: List([
          Map({ id: '1', userUuid: '1', bankId: '1', permission: CAN_EDIT, full_name: 'first FullName', avatar: 'http://avatars.com/avatar1' }),
          Map({ id: '2', userUuid: '2', bankId: '1', permission: CAN_EDIT, full_name: 'second FullName', avatar: 'http://avatars.com/avatar2' })
        ])
      })
      expect(testbed.getText()).to.not.include('Loading...')
    })
  })
})
