import { fromJS, List } from 'immutable'

import reducer from '../tagAssociations'

import * as actions from '../../actions/tagAssociations'
import { addItems } from '../../actions/items'
import { addStimuli } from '../../actions/stimuli'

describe('tag associations reducer', () => {
  const initialState = fromJS({
    Item: {
      2: [
        {
          id: '99',
          tag_value: 'boo'
        },
        {
          id: '100',
          tag_value: 'moo'
        }
      ]
    },
    pendingAddition: {
      Item: {
        1: [{
          tag_value: 'tag-1'
        }]
      }
    },
    pendingDeletion: {
      Item: {
        1: [{
          id: '1'
        }]
      }
    }
  })

  describe('addTagAssociation', () => {
    it('creates new tag association list', () => {
      const action = actions.addTagAssociation('Item', '1', {id: '101', tag_value: 'zoo'})
      const nextState = reducer(initialState, action)

      expect(nextState.getIn(['Item', '1']).size).to.eq(1)
    })

    it('append tag association to existing list', () => {
      const action = actions.addTagAssociation('Item', '2', {id: '101', tag_value: 'zoo'})
      const nextState = reducer(initialState, action)

      expect(nextState.getIn(['Item', '2']).size).to.eq(3)
    })
  })

  describe('removePendingAdditionTagAssociation', () => {
    it('removes a pending addition tag association', () => {
      const action = actions.removePendingAdditionTagAssociation('Item', '1', 'tag-1')
      const nextState = reducer(initialState, action)

      expect(nextState.getIn(['pendingAddition', 'Item', '1']).size).to.eq(0)
    })
  })

  describe('removePendingDeletionTagAssociation', () => {
    it('removes a pending deletion tag association', () => {
      const action = actions.removePendingDeletionTagAssociation('Item', '1', '1')
      const nextState = reducer(initialState, action)

      expect(nextState.getIn(['pendingDeletion', 'Item', '1']).size).to.eq(0)
    })
  })

  describe('removeTagAssociation', () => {
    it('removes given tag', () => {
      const action = actions.removeTagAssociation('Item', '2', '99')
      const nextState = reducer(initialState, action)

      expect(nextState.getIn(['Item', '2']).size).to.eq(1)
      expect(nextState.getIn(['Item', '2', 0, 'id'])).to.eq('100')
    })

    it('removes no tag', () => {
      const action = actions.removeTagAssociation('Item', '2', '191')
      const nextState = reducer(initialState, action)

      expect(nextState.getIn(['Item', '2']).size).to.eq(2)
    })
  })

  describe('setPendingAdditionTagAssociations', () => {
    it('sets pending addition tag associations', () => {
      const action = actions.setPendingAdditionTagAssociations('Item', '2', [{id: '99', tag_value: 'boo'}])
      const nextState = reducer(initialState, action)
      expect(nextState.getIn(['pendingAddition', 'Item', '2']).size).to.eq(1)
    })
  })

  describe('setPendingDeletionTagAssociations', () => {
    it('sets pending tag deletions', () => {
      const action = actions.setPendingDeletionTagAssociations('Item', '2', [{id: '99', tag_value: 'boo'}])
      const nextState = reducer(initialState, action)
      expect(nextState.getIn(['pendingDeletion', 'Item', '2']).size).to.eq(1)
    })
  })

  describe('setTags', () => {
    it('sets item tags', () => {
      const action = addItems(
        [
          {id: '1', tagAssociations: [{id: '2', tagValue: 'blue', tagId: '3'}]},
          {id: '2', tagAssociations: [{id: '4', tagValue: 'redx', tagId: '5'}]}
        ]
      )
      const nextState = reducer(initialState, action)
      expect(nextState.getIn(['Item', '1']).toJS()).to.deep.eq(
        [{id: '2', tag_value: 'blue', tag_id: '3'}]
      )
      expect(nextState.getIn(['Item', '2']).toJS()).to.deep.eq(
        [{id: '4', tag_value: 'redx', tag_id: '5'}]
      )
    })

    it('sets stimulus tags', () => {
      const action = addStimuli(
        [
          {id: '1', tagAssociations: [{id: '2', tagValue: 'blue', tagId: '3'}]},
          {id: '2', tagAssociations: [{id: '4', tagValue: 'redx', tagId: '5'}]}
        ]
      )
      const nextState = reducer(initialState, action)
      expect(nextState.getIn(['Stimulus', '1']).toJS()).to.deep.eq(
        [{id: '2', tag_value: 'blue', tag_id: '3'}]
      )
      expect(nextState.getIn(['Stimulus', '2']).toJS()).to.deep.eq(
        [{id: '4', tag_value: 'redx', tag_id: '5'}]
      )
    })
  })

  describe('setTagInput', () => {
    it('sets the tag input', () => {
      const action = actions.setTagInput('Item', '1', 'hello')
      const nextState = reducer(initialState, action)

      expect(nextState.getIn(['tagInput', 'Item', '1'])).to.eq('hello')
    })
  })

  describe('setTagSuggestions', () => {
    it('sets tag suggestions', () => {
      const inputAction = actions.setTagInput('Item', '1', 'hi')
      const startState = reducer(initialState, inputAction)

      const action = actions.setTagSuggestions('Item', '1', [], 'hi')
      const nextState = reducer(startState, action)

      expect(nextState.getIn(['tagSuggestions', 'Item', '1'])).to.eq(List())
    })

    it('does not set tag suggestions since tag input has changed', () => {
      const inputAction = actions.setTagInput('Item', '1', 'hig')
      const startState = reducer(initialState, inputAction)

      const action = actions.setTagSuggestions('Item', '1', [], 'hi')
      const nextState = reducer(startState, action)

      expect(nextState.getIn(['tagSuggestions', 'Item', '1'])).to.be.undefined()
    })
  })

  describe('default', () => {
    it('does not update state', () => {
      const action = { action: 'IRRELEVANT_ACTION', payload: [] }
      const nextState = reducer(initialState, action)

      expect(nextState).to.eq(initialState)
    })
  })
})
