/* eslint-disable prettier/prettier */
import { mutations, updateTags } from '@/store/modules/data/tags.js'

const TEST_SLOT = 0
function fillSlot(state) {
  return { 0: { links: {}, ...state } }
}

describe('store/data/tags/TAG_NODES', () => {
  it('adds 1 tag to 1 regular node', () => {
    const nodes = [
      { id: 0, type: 'regular', vis: { tags: [] } },
      { id: 1, type: 'regular', vis: { tags: [] } },
      { id: 2, type: 'regular', vis: { tags: [] } }
    ]
    const payload = {
        slotId: TEST_SLOT,
        arr: [0],
        id: 0,
        name: 'first',
        color: 'black'
      },
      state = fillSlot({ tags: [], nodes: nodes, lastTag: {} }),
      tag0 = {
        id: 0,
        name: 'first',
        groupNodeId: null,
        assignedObjectsIds: [0],
        isVisualized: true,
        color: 'black',
        stroke: 'none',
        type: 'manual'
      },
      expectedState = {
        tags: [tag0],
        nodes: nodes,
        lastTag: tag0
      }

    mutations.TAG_NODES(state, payload)
    expect(state).toEqual(fillSlot(expectedState))
  })

  it('adds 1 tag without specified tag name to 1 regular node', () => {
    const nodes = [
      { id: 0, type: 'regular', vis: { tags: [] } },
      { id: 1, type: 'regular', vis: { tags: [] } },
      { id: 2, type: 'regular', vis: { tags: [] } }
    ]
    const payload = {
        slotId: TEST_SLOT,
        arr: [1],
        id: 0,
        name: '',
        color: ''
      },
      state = fillSlot({ tags: [], nodes: nodes, lastTag: {} }),
      tag0 = {
        id: 0,
        name: 'group 0',
        groupNodeId: null,
        assignedObjectsIds: [1],
        isVisualized: true,
        color: 'none',
        stroke: '#000000',
        type: 'manual'
      },
      expectedState = {
        tags: [tag0],
        nodes: nodes,
        lastTag: tag0
      }

    mutations.TAG_NODES(state, payload)

    expect(state).toEqual(fillSlot(expectedState))
  })

  // still manual, other types are only assigned through AGGREGATE_NODES
  // so it has to be tested in data store
  it('adds 1 tag to group node', () => {
    const nodes = [
      { id: 0, type: 'regular', vis: { tags: [] } },
      { id: 1, type: 'group', vis: { tags: [] } },
      { id: 2, type: 'regular', vis: { tags: [] } }
    ]
    const payload = {
        slotId: TEST_SLOT,
        arr: [1],
        id: 0,
        name: 'name',
        color: '#FFFFFF'
      },
      state = fillSlot({ tags: [], nodes: nodes, lastTag: {} }),
      tag0 = {
        id: 0,
        name: 'name',
        groupNodeId: null,
        assignedObjectsIds: [1],
        isVisualized: true,
        color: '#FFFFFF',
        stroke: 'none',
        type: 'manual'
      },
      expectedState = {
        tags: [tag0],
        nodes: nodes,
        lastTag: tag0
      }

    mutations.TAG_NODES(state, payload)

    expect(state).toEqual(fillSlot(expectedState))
  })

  it('adds second tag to multiple regular nodes', () => {
    const nodes = [
      { id: 0, type: 'regular', vis: { tags: [] } },
      { id: 1, type: 'group', vis: { tags: [] } },
      { id: 2, type: 'regular', vis: { tags: [] } }
    ]
    const payload = {
        slotId: TEST_SLOT,
        arr: [0, 2],
        id: 1,
        name: 'second',
        color: 'black'
    }
    const tag0 = {
        id: 0,
        name: 'first',
        groupNodeId: null,
        assignedObjectsIds: [0, 1, 2],
        isVisualized: true,
        color: 'black',
        stroke: 'none',
        type: 'manual'
      }
    const tag1 = {
        id: 1,
        name: 'second',
        groupNodeId: null,
        assignedObjectsIds: [0, 2],
        isVisualized: true,
        color: 'black',
        stroke: 'none',
        type: 'manual'
      }
    const state = fillSlot({
        tags: [tag0],
        nodes: nodes,
        lastTag: 0
      })
    const expectedState = {
        tags: [tag0, tag1],
        nodes: nodes,
        lastTag: tag1
      }

    mutations.TAG_NODES(state, payload)

    expect(state).toEqual(fillSlot(expectedState))
  })

  // should throw
  it('try to add the tag with the same name to node which already has it', () => {
    const nodes = [
      { id: 0, type: 'regular', vis: { tags: [] } },
      { id: 1, type: 'group', vis: { tags: [] } },
      { id: 2, type: 'regular', vis: { tags: [] } }
    ]
    const payload = {
        slotId: TEST_SLOT,
        arr: [0],
        id: 0,
        name: 'name',
        color: 'black'
      },
      tag0 = {
        id: 0,
        name: 'name',
        groupNodeId: null,
        assignedObjectsIds: [0, 1, 2],
        isVisualized: true,
        color: 'black',
        stroke: 'none',
        type: 'manual'
      },
      state = fillSlot({
        tags: [tag0],
        nodes: nodes,
        lastTag: tag0
      }),
      expectedState = {
        tags: [tag0],
        nodes: nodes,
        lastTag: tag0
      }

    expect(() => {
      mutations.TAG_NODES(state, payload)
    }).toThrow()

    expect(state).toEqual(fillSlot(expectedState))
  })

  // should pass - we can have a selection "classmates" and "murderers"
  it('try to add the tag to the same array of assigned nodes', () => {
    const nodes = [
      { id: 0, type: 'regular', vis: { tags: [] } },
      { id: 1, type: 'group', vis: { tags: [] } },
      { id: 2, type: 'regular', vis: { tags: [] } }
    ]
    const payload = {
        slotId: TEST_SLOT,
        arr: [0, 1, 2],
        id: 1,
        name: 'different_name',
        color: 'black'
      },
      tag0 = {
        id: 0,
        name: 'name',
        groupNodeId: null,
        assignedObjectsIds: [0, 1, 2],
        isVisualized: true,
        color: 'black',
        stroke: 'none',
        type: 'manual'
      },
      tag1 = {
        id: 1,
        name: 'different_name',
        groupNodeId: null,
        assignedObjectsIds: [0, 1, 2],
        isVisualized: true,
        color: 'black',
        stroke: 'none',
        type: 'manual'
      },
      state = fillSlot({
        tags: [tag0],
        nodes: nodes,
        lastTag: tag0
      }),
      expectedState = {
        tags: [tag0, tag1],
        nodes: nodes,
        lastTag: tag1
      }

    mutations.TAG_NODES(state, payload)

    expect(state).toEqual(fillSlot(expectedState))
  })
})

describe('store/data/tags/helpers: updateTags', () => {
  it('simulate grouping by updating tag on grouped nodes', () => {
    const nodesToGroupIds = [0, 1],
      action = 'group',
      groupNode = { id: 3, type: 'group', label: 'group label', vis: { tags: [] } },
      stateNodes = [
        { id: 0, type: 'regular', vis: { tags: [] } },
        { id: 1, type: 'regular', vis: { tags: [] } },
        { id: 2, type: 'regular', vis: { tags: [] } },
        groupNode
      ],
      tag0 = {
        id: 0,
        name: 'group label',
        groupNodeId: groupNode.id,
        assignedObjectsIds: [0, 1],
        isVisualized: true,
        color: '#000000',
        stroke: 'none',
        type: 'group'
      }

    const state = {
        tags: []
      },
      expectedState = {
        tags: [tag0]
      }

    updateTags(state.tags, stateNodes, nodesToGroupIds, action, groupNode, '#000000')

    expect(state).toEqual(expectedState)
  })

  // TODO should it also update the tag name to group label? (it does now)
  // assign tag to nodes which already have it, but didnt have group node
  it('updates tag to have a group node', () => {
    const nodesToGroupIds = [0, 1],
      action = 'group',
      groupNode = { id: 3, type: 'group', label: 'group label', vis: { tags: [] } },
      stateNodes = [
        { id: 0, type: 'regular', vis: { tags: [] } },
        { id: 1, type: 'regular', vis: { tags: [] } },
        { id: 2, type: 'regular', vis: { tags: [] } },
        groupNode
      ],
      tag0 = {
        id: 0,
        name: 'group 0',
        assignedObjectsIds: [0, 1],
        isVisualized: true,
        color: '#000000',
        stroke: 'none',
        type: 'manual'
      }

    const state = {
        tags: [tag0]
      },
      expectedState = {
        tags: [
          {
            id: 0,
            name: 'group label',
            groupNodeId: groupNode.id,
            assignedObjectsIds: [0, 1],
            isVisualized: true,
            color: '#000000',
            stroke: 'none',
            type: 'group'
          }
        ]
      }

    updateTags(state.tags, stateNodes, nodesToGroupIds, action, groupNode, '#000000')

    expect(state).toEqual(expectedState)
  })

  it('bundle into existing bundle', () => {
    const nodesToGroupIds = [2],
      action = 'bundle',
      groupNode = { id: 3, type: 'bundle', label: 'group label', vis: { tags: [] } },
      stateNodes = [
        { id: 0, type: 'regular', vis: { tags: [] } },
        { id: 1, type: 'regular', vis: { tags: [] } },
        { id: 2, type: 'regular', vis: { tags: [] } },
        groupNode
      ],
      tag0 = {
        id: 0,
        name: 'group 0',
        groupNodeId: groupNode.id,
        assignedObjectsIds: [0, 1],
        isVisualized: true,
        color: '#000000',
        stroke: 'none',
        type: 'bundle'
      }

    const state = {
        tags: [tag0]
      },
      expectedState = {
        tags: [
          {
            id: 0,
            name: 'group label',
            groupNodeId: groupNode.id,
            assignedObjectsIds: [0, 1, 2],
            isVisualized: true,
            color: '#000000',
            stroke: 'none',
            type: 'bundle'
          }
        ]
      }

    updateTags(state.tags, stateNodes, nodesToGroupIds, action, groupNode, '#000000')

    expect(state).toEqual(expectedState)
  })

  // TODO: test hierarchy of grouping--agregation of tags
  it('bundle into existing group', () => {
    const nodesToGroupIds = [2],
      action = 'bundle',
      groupNode = { id: 3, type: 'group', label: 'group 0', vis: { tags: [] } },
      stateNodes = [
        { id: 0, type: 'regular', vis: { tags: [] } },
        { id: 1, type: 'regular', vis: { tags: [] } },
        { id: 2, type: 'regular', vis: { tags: [] } },
        groupNode
      ],
      tag0 = {
        id: 0,
        name: 'group 0',
        groupNodeId: groupNode.id,
        assignedObjectsIds: [0, 1],
        isVisualized: true,
        color: '#000000',
        stroke: 'none',
        type: 'group'
      }

    const state = {
        tags: [tag0]
      },
      expectedState = {
        tags: [
          {
            id: 0,
            name: 'group 0',
            groupNodeId: groupNode.id,
            assignedObjectsIds: [0, 1, 2],
            isVisualized: true,
            color: '#000000',
            stroke: 'none',
            type: 'group'
          }
        ]
      }

    updateTags(state.tags, stateNodes, nodesToGroupIds, action, groupNode, '#000000')

    expect(state).toEqual(expectedState)
  })

  it('group two groups', () => {
    const nodesToGroupIds = [3, 5],
      action = 'group',
      groupNode = { id: 3, type: 'group', label: 'group 0', vis: { tags: [] } },
      groupNode2 = { id: 5, type: 'group', label: 'group 1', vis: { tags: [] } },
      groupNode3 = { id: 6, type: 'group', label: 'group 2', vis: { tags: [] } },
      stateNodes = [
        { id: 0, type: 'regular', vis: { tags: [] } },
        { id: 1, type: 'regular', vis: { tags: [] } },
        { id: 2, type: 'regular', vis: { tags: [] } },
        groupNode,
        { id: 4, type: 'regular', vis: { tags: [] } },
        groupNode2,
        groupNode3
      ]

    const state = {
        tags: [
          {
            id: 0,
            name: 'group 0',
            groupNodeId: groupNode.id,
            assignedObjectsIds: [0, 1],
            isVisualized: true,
            color: '#000000',
            stroke: 'none',
            type: 'group'
          },
          {
            id: 1,
            name: 'group 1',
            groupNodeId: groupNode2.id,
            assignedObjectsIds: [2, 4],
            isVisualized: true,
            color: '#000000',
            stroke: 'none',
            type: 'group'
          }
        ]
      },
      expectedState = {
        tags: [
          {
            id: 0,
            name: 'group 0',
            groupNodeId: groupNode.id,
            assignedObjectsIds: [0, 1],
            isVisualized: true,
            color: '#000000',
            stroke: 'none',
            type: 'group'
          },
          {
            id: 1,
            name: 'group 1',
            groupNodeId: groupNode2.id,
            assignedObjectsIds: [2, 4],
            isVisualized: true,
            color: '#000000',
            stroke: 'none',
            type: 'group'
          },
          {
            id: 2,
            name: 'group 2',
            groupNodeId: groupNode3.id,
            assignedObjectsIds: [3, 5],
            isVisualized: true,
            color: '#000000',
            stroke: 'none',
            type: 'group'
          }
        ]
      }

    updateTags(state.tags, stateNodes, nodesToGroupIds, action, groupNode3, '#000000')

    expect(state).toEqual(expectedState)
  })

  it('alias two aggregations (group and a bundle)', () => {
    const nodesToGroupIds = [3, 5],
      action = 'alias',
      groupNode = { id: 3, type: 'group', label: 'group 0', vis: { tags: [] } },
      groupNode2 = { id: 5, type: 'bundle', label: 'group 1', vis: { tags: [] } },
      groupNode3 = { id: 6, type: 'alias', label: 'group 2', vis: { tags: [] } },
      stateNodes = [
        { id: 0, type: 'regular', vis: { tags: [] } },
        { id: 1, type: 'regular', vis: { tags: [] } },
        { id: 2, type: 'regular', vis: { tags: [] } },
        groupNode,
        { id: 4, type: 'regular', vis: { tags: [] } },
        groupNode2,
        groupNode3
      ]

    const state = {
        tags: [
          {
            id: 0,
            name: 'group 0',
            groupNodeId: groupNode.id,
            assignedObjectsIds: [0, 1],
            isVisualized: true,
            color: '#000000',
            stroke: 'none',
            type: 'group'
          },
          {
            id: 1,
            name: 'group 1',
            groupNodeId: groupNode2.id,
            assignedObjectsIds: [2, 4],
            isVisualized: true,
            color: '#000000',
            stroke: 'none',
            type: 'bundle'
          }
        ]
      },
      expectedState = {
        tags: [
          {
            id: 0,
            name: 'group 0',
            groupNodeId: groupNode.id,
            assignedObjectsIds: [0, 1],
            isVisualized: true,
            color: '#000000',
            stroke: 'none',
            type: 'group'
          },
          {
            id: 1,
            name: 'group 1',
            groupNodeId: groupNode2.id,
            assignedObjectsIds: [2, 4],
            isVisualized: true,
            color: '#000000',
            stroke: 'none',
            type: 'bundle'
          },
          {
            id: 2,
            name: 'group 2',
            groupNodeId: groupNode3.id,
            assignedObjectsIds: [3, 5],
            isVisualized: true,
            color: '#000000',
            stroke: 'none',
            type: 'alias'
          }
        ]
      }

    updateTags(state.tags, stateNodes, nodesToGroupIds, action, groupNode3, '#000000')

    expect(state).toEqual(expectedState)
  })
})
