import { diffDB, collectMutations, transformArrayToDB } from '../utils'
import { transform } from 'lodash'
const typesFalsy = {
  number: 0,
  boolean: false,
  string: '',
  array: [],
  object: {},
  undefined: undefined,
  null: null,
}
const expectedFalsy = {
  number: 0,
  boolean: false,
  string: '',
  array: [],
  null: null,
}
const typesTruthy = {
  number: 12,
  boolean: true,
  string: 'hello!',
  array: [1, 2, 3],
  object: { a: 1, b: 2 },
  undefined: 'not undefined',
  null: 45,
}
const dbId = 'dbId'
const createId = '++fakeId'
const deleteId = '--dbId'
const newContent = {
  id: createId,
  some: 'new content',
  an: ['array', 'of', 'new', 'items'],
}
const originalContent = {
  id: 'dbChildId',
  some: 'original content',
  an: ['array', 'of', 'strings'],
}
const changedContent = {
  id: 'dbChildId',
  some: 'changed content',
  an: ['array', 'of', 'more', 'strings'],
}

const dbItem = {
  id: dbId,
  unchangedChild: originalContent,
  updatedChild: originalContent,
  deletedChild: originalContent,
  nestedChild: { ...originalContent, child: originalContent },
}

describe('diffDB: Find differences of current state to database', () => {
  it('returns undefined if there are no differences', () => {
    const truthyNoDiffs = diffDB(typesTruthy, typesTruthy)
    expect(truthyNoDiffs).toBe(undefined)
    const falsyNoDiffs = diffDB(typesFalsy, typesFalsy)
    expect(falsyNoDiffs).toBe(undefined)
  })
  it('diffs types correctly', () => {
    const truthyDiff = diffDB(typesTruthy, typesFalsy)
    expect(truthyDiff).toEqual(typesTruthy)
    const falsyDiff = diffDB(typesFalsy, typesTruthy)
    expect(falsyDiff).toEqual(expectedFalsy)
  })

  const updateItem = {
    id: dbId,
    unchangedChild: originalContent,
    createdChild: newContent,
    updatedChild: changedContent,
    deletedChild: { ...changedContent, id: deleteId },
    nestedChild: { ...originalContent, child: changedContent },
  }
  it('diffs nested items correctly', () => {
    expect(diffDB(updateItem, dbItem)).toEqual({
      id: '@@dbId',
      createdChild: newContent,
      updatedChild: { ...changedContent, id: '@@dbChildId' },
      deletedChild: { id: deleteId },
      nestedChild: {
        id: '@@dbChildId',
        child: { ...changedContent, id: '@@dbChildId' },
      },
    })
  })

  const createItem = {
    id: createId,
    createdChild: newContent,
    newNestedChild: { ...newContent, child: newContent },
    originalNestedChild: { ...newContent, child: originalContent },
  }
  it('diffs nested items correctly', () => {
    expect(diffDB(createItem, dbItem)).toEqual({
      id: createId,
      createdChild: newContent,
      newNestedChild: { ...newContent, child: newContent },
      originalNestedChild: { ...newContent, child: originalContent },
    })
  })
})

const collection = [
  { create: originalContent },
  { update: changedContent },
  { delete: changedContent },
  { update: originalContent },
  { connect: originalContent },
]
const stringArray = ['do', 'not', 'touch']
describe('collects DB changes.', () => {
  it('collects array of mutations', () => {
    expect(collectMutations(collection)).toEqual({
      create: [originalContent],
      update: [changedContent, originalContent],
      delete: [changedContent],
      connect: [originalContent],
    })
  })
  it('creates sets of string arrays.', () => {
    expect(collectMutations(stringArray)).toEqual({ set: stringArray })
  })
})

describe('transforms form data to DB data', () => {
  const updateData = {
    id: '@@toUpdate',
    value: '14',
    child: { id: '--toDelete' },
    children: [
      { id: '++toCreate', value: 'nice' },
      { id: '@@toUpdate', value: 'good' },
      { id: 'toConnect', value: 'fine' },
    ],
    arrays: ['do', 'not', 'touch', 'strings'],
  }
  it('updates records.', () => {
    expect(transform(updateData, transformArrayToDB)).toEqual({
      id: '@@toUpdate',
      value: '14',
      child: { delete: { id: 'toDelete' } },
      children: {
        create: [{ value: 'nice' }],
        update: [{ where: { id: 'toUpdate' }, data: { value: 'good' } }],
        connect: [{ id: 'toConnect' }],
      },
      arrays: { set: ['do', 'not', 'touch', 'strings'] },
    })
  })

  const createData = {
    id: '++toCreate',
    value: '14',
    child: { id: '--toDelete' },
    children: [
      { id: '++toCreate', value: 'nice' },
      { id: '@@toUpdate', value: 'good' },
      { id: 'toConnect', value: 'fine' },
    ],
    arrays: ['do', 'not', 'touch', 'strings'],
  }
  it('creates records.', () => {
    expect(transform(createData, transformArrayToDB)).toEqual({
      value: '14',
      child: { delete: { id: 'toDelete' } },
      children: {
        create: [{ value: 'nice' }],
        update: [{ where: { id: 'toUpdate' }, data: { value: 'good' } }],
        connect: [{ id: 'toConnect' }],
      },
      arrays: { set: ['do', 'not', 'touch', 'strings'] },
    })
  })
})
