import { EditorSession, MemoryDOMElement } from 'substance'
import {
  TableComponent, TextureDocument, TextureConfigurator, tableHelpers,
  EditorPackage, TableEditing
} from 'substance-texture'
import { testAsync, getMountPoint } from '../testHelpers'

testAsync('TableComponent: mounting a table component', async (t) => {
  let { table, context } = _setup(t)
  let el = getMountPoint(t)
  let comp = new TableComponent(null, { node: table }, { context })
  comp.mount(el)
  t.notNil(el.find('.sc-table'), 'there should be a rendered table element')
  t.end()
})

testAsync('TableComponent: setting table selections', async (t) => {
  let { editorSession, table, context } = _setup(t)
  let el = getMountPoint(t)
  let comp = new TableComponent(null, { node: table }, { context })
  comp.mount(el)
  let matrix = table.getCellMatrix()
  let firstCell = matrix[0][0]
  let tableEditing = new TableEditing(editorSession, table.id, comp.getSurfaceId())
  // setting the selection on the first cell
  let sel = tableEditing.createTableSelection({
    anchorCellId: firstCell.id,
    focusCellId: firstCell.id
  })
  editorSession.setSelection(sel)
  t.equal(comp.refs.selAnchor.el.css('visibility'), 'visible', 'the selection overlay for the selection anchor should be visible')
  t.equal(comp.refs.selRange.el.css('visibility'), 'visible', 'the selection overlay for the selection range should be visible')

  // setting the selection inside the first cell
  editorSession.setSelection({
    type: 'property',
    path: firstCell.getPath(),
    startOffset: 0,
    endOffset: 0
  })
  t.equal(comp.refs.selAnchor.el.css('visibility'), 'visible', 'the selection overlay for the selection anchor should be visible')
  t.equal(comp.refs.selRange.el.css('visibility'), 'hidden', 'the selection overlay for the selection range should be hidden')

  // nulling the selection
  editorSession.setSelection(null)
  t.equal(comp.refs.selAnchor.el.css('visibility'), 'hidden', 'the selection overlay for the selection anchor should be hidden')
  t.equal(comp.refs.selRange.el.css('visibility'), 'hidden', 'the selection overlay for the selection range should be hidden')

  t.end()
})

testAsync('TableComponent: mouse interactions', async (t) => {
  let { editorSession, table, context } = _setup(t)
  let el = getMountPoint(t)
  let comp = new TableComponent(null, { node: table }, { context })
  comp.mount(el)
  let matrix = table.getCellMatrix()
  let firstCell = matrix[0][0]
  let firstCellComp = comp.refs[firstCell.id]

  comp._onMousedown(new MouseEvent(firstCellComp.el))

  let sel = editorSession.getSelection()
  t.equal(sel.customType, 'table', 'The table should be selection,')
  t.equal(sel.data.anchorCellId, firstCell.id, '.. with anchor on first cell,')
  t.equal(sel.data.focusCellId, firstCell.id, '.. and focus on first cell,')

  t.end()
})

function _setup (t) {
  let configurator = new TextureConfigurator()
  configurator.import(EditorPackage)
  let doc = _createEmptyTextureArticle(configurator)
  let table = tableHelpers.generateTable(doc, 10, 5)
  doc.find('body > body-content').append(table)
  // TODO: look closely here: this is the footprint of how context
  // is used by TableComponent and children
  let editorSession = new EditorSession(doc, { configurator })
  let componentRegistry = configurator.getComponentRegistry()
  let commandGroups = configurator.getCommandGroups()
  let iconProvider = configurator.getIconProvider()
  let labelProvider = configurator.getLabelProvider()
  let keyboardShortcuts = configurator.getKeyboardShortcuts()
  let tools = configurator.getTools()
  let context = {
    editorSession,
    configurator,
    componentRegistry,
    commandGroups,
    tools,
    iconProvider,
    labelProvider,
    keyboardShortcuts
  }
  return { context, editorSession, doc, table }
}

function _createEmptyTextureArticle (configurator) {
  let doc = new TextureDocument(configurator.getSchema())
  doc.$$ = doc.createElement.bind(doc)
  const $$ = doc.$$
  $$('article', { id: 'article' }).append(
    $$('front').append(
      $$('article-meta').append(
        $$('title-group').append(
          $$('article-title')
        ),
        $$('abstract')
      )
    ),
    $$('body').append(
      $$('body-content')
    ),
    $$('back')
  )
  return doc
}

// FIXME: add compatibility stub implementations
MemoryDOMElement.prototype.getBoundingClientRect = function () {
  return { top: 0, left: 0, height: 0, width: 0 }
}

MemoryDOMElement.prototype.getClientRects = function () {
  return [{ top: 0, left: 0, height: 0, width: 0 }]
}

class MouseEvent {
  constructor (target) {
    this.target = target
  }
  stopPropagation () {}
  preventDefault () {}
}

@@ -2510,16 +2510,141 @@
 ell.id%5D%0A
+  let secondCell = matrix%5B0%5D%5B1%5D%0A  let secondCellComp = comp.refs%5BsecondCell.id%5D%0A%0A  // simulate a mouse down on the first cell
 %0A  comp.
@@ -2671,16 +2671,26 @@
 seEvent(
+%7B target: 
 firstCel
@@ -2701,12 +2701,13 @@
 p.el
+ %7D
 ))%0A
-%0A
   le
@@ -2966,24 +2966,384 @@
 st cell,')%0A%0A
+  // simulate a right mouse down on the second cell%0A  comp._onMousedown(new MouseEvent(%7B target: secondCellComp.el, which: 3 %7D))%0A  t.equal(sel.customType, 'table', 'The table should be selection,')%0A  t.equal(sel.data.anchorCellId, secondCell.id, '.. with anchor on second cell,')%0A  t.equal(sel.data.focusCellId, secondCell.id, '.. and focus on second cell,')%0A%0A
   t.end()%0A%7D)
@@ -5113,22 +5113,21 @@
 or (
-target
+props
 ) %7B%0A    
 this
@@ -5126,28 +5126,34 @@
     
-this.target = target
+Object.assign(this, props)
 %0A  %7D

Add a test revealing a bug in TableComponent's right click handling.