import { TreeGraph } from '../../../src';
import { timerOut } from '../util/timeOut';

const div = document.createElement('div');
div.id = 'tree-spec';
document.body.appendChild(div);

describe('tree graph without animate', () => {
  let graph = new TreeGraph({
    container: div,
    width: 500,
    height: 500,
    animate: false,
    modes: {
      default: ['drag-canvas', 'drag-node'],
    },
    layout: {
      type: 'dendrogram',
      direction: 'LR', // H / V / LR / RL / TB / BT
      nodeSep: 50,
      rankSep: 100,
    },
  });

  it('layout init & findDataById', () => {
    const data = {
      isRoot: true,
      id: 'Root',
      children: [
        {
          id: 'SubTreeNode1',
          children: [
            {
              id: 'SubTreeNode1.1',
            },
            {
              id: 'SubTreeNode1.2',
            },
          ],
        },
        {
          id: 'SubTreeNode2',
        },
      ],
    };
    graph.data(data);
    graph.render();
    graph.fitView();

    expect(Object.keys(graph.get('itemMap')).length).toBe(9);

    const edge = graph.findById('Root:SubTreeNode1');
    expect(edge).not.toBe(undefined);

    expect(edge.get('source')).toEqual(graph.findById('Root'));
    expect(edge.get('target')).toEqual(graph.findById('SubTreeNode1'));

    expect(graph.save()).toEqual(data);

    // findDataById
    const nodeData = graph.findDataById('Root', data);
    expect(nodeData).toEqual(data);
  });

  it('layout without data & isLayoutAnimating', () => {
    graph.data(null);
    expect(() => {
      graph.render();
    }).toThrowError('data must be defined first');

    graph.stopLayoutAnimate();
    expect(graph.isLayoutAnimating()).toBe(false);
  });

  it('changeData', () => {
    const data = {
      isRoot: true,
      id: 'Root',
      children: [
        {
          id: 'SubTreeNode1',
          children: [
            {
              id: 'SubTreeNode1.1',
            },
            {
              id: 'SubTreeNode1.2',
            },
          ],
        },
        {
          id: 'SubTreeNode3',
        },
        {
          id: 'SubTreeNode4',
          children: [{ id: 'SubTreeNode4.1' }],
        },
      ],
    };
    graph.changeData(data);
    expect(graph.save()).toEqual(data);

    expect(Object.keys(graph.get('itemMap')).length).toBe(13);
    expect(graph.findById('SubTreeNode2')).toBe(undefined);
    expect(graph.findById('SubTreeNode3')).not.toBe(undefined);
    expect(graph.findById('SubTreeNode4')).not.toBe(undefined);

    const edge = graph.findById('SubTreeNode4:SubTreeNode4.1');
    expect(edge).not.toBe(undefined);
    expect(edge.get('source')).toEqual(graph.findById('SubTreeNode4'));
    expect(edge.get('target')).toEqual(graph.findById('SubTreeNode4.1'));
  });

  it('add child', () => {
    const parent = graph.findById('SubTreeNode3');

    const child = {
      id: 'SubTreeNode3.1',
      x: 100,
      y: 100,
      type: 'rect',
      children: [{ x: 150, y: 150, id: 'SubTreeNode3.1.1' }],
    };
    graph.on('afteraddchild', function (e) {
      expect(
        e.item.getModel().id === 'SubTreeNode3.1' || e.item.getModel().id === 'SubTreeNode3.1.1',
      ).toBe(true);
      expect(
        e.item.get('parent').getModel().id === 'SubTreeNode3' ||
          e.item.get('parent').getModel().id === 'SubTreeNode3.1',
      ).toBe(true);
      expect(
        e.parent.getModel().id === 'SubTreeNode3' || e.parent.getModel().id === 'SubTreeNode3.1',
      ).toBe(true);
    });

    graph.addChild(child, parent);

    const children = parent.get('model').children;
    expect(children).not.toBe(undefined);
    expect(children.length).toBe(1);
    expect(children[0].id).toEqual('SubTreeNode3.1');

    expect(graph.findById('SubTreeNode3.1')).not.toBe(undefined);
    expect(graph.findById('SubTreeNode3:SubTreeNode3.1')).not.toBe(undefined);
    expect(graph.findById('SubTreeNode3.1.1')).not.toBe(undefined);
    expect(graph.findById('SubTreeNode3.1:SubTreeNode3.1.1')).not.toBe(undefined);
  });

  it('remove child & remove nonexistent child', () => {
    graph.removeChild('SubTreeNode3.1');

    const parent = graph.findById('SubTreeNode3');
    const children = parent.get('model').children;

    expect(children.length).toBe(0);
    expect(graph.findById('SubTreeNode3.1')).toBe(undefined);
    expect(graph.findById('SubTreeNode3:SubTreeNode3.1')).toBe(undefined);
    expect(graph.findById('SubTreeNode3.1.1')).toBe(undefined);
    expect(graph.findById('SubTreeNode3.1:SubTreeNode3.1.1')).toBe(undefined);

    const none = graph.removeChild('none-child');
    expect(none).toBe(undefined);
  });

  it('collapse & expand with layout', () => {
    const parent = graph.findById('SubTreeNode1');
    let child = graph.findById('SubTreeNode1.1');
    let collapsed = true;
    graph.on('afterrefreshlayout', () => {
      if (collapsed) {
        expect(parent.getModel().collapsed).toBe(true);
        expect(child.destroyed).toBe(true);
      } else {
        child = graph.findById('SubTreeNode1.1');
        expect(parent.getModel().collapsed).toBe(false);
        expect(child.get('model').x).not.toEqual(parent.get('model').x);
        expect(!!child.getModel().collapsed).toBe(false);
        expect(child.get('model').y).not.toEqual(parent.get('model').y);
      }
    });
    graph.addBehaviors('collapse-expand', 'default');
    graph.emit('node:click', { item: parent });
    timerOut(() => {
      collapsed = false;
      graph.emit('node:click', { item: parent });
    }, 600);
    // graph.destroy();
  });

  it('collapse & expand with layout with parameter trigger=dblclick', () => {
    graph = new TreeGraph({
      container: div,
      width: 500,
      height: 500,
      animate: false,
      modes: {
        default: ['drag-canvas', 'drag-node'],
      },
      layout: {
        type: 'dendrogram',
        direction: 'LR', // H / V / LR / RL / TB / BT
        nodeSep: 50,
        rankSep: 100,
      },
    });
    const data = {
      isRoot: true,
      id: 'Root',
      children: [
        {
          id: 'SubTreeNode1',
          children: [
            {
              id: 'SubTreeNode1.1',
            },
            {
              id: 'SubTreeNode1.2',
            },
          ],
        },
        {
          id: 'SubTreeNode2',
        },
      ],
    };
    graph.data(data);
    graph.render();
    const parent = graph.findById('SubTreeNode1');
    parent.getModel().label = 'parent';
    let child = graph.findById('SubTreeNode1.1');
    let collapsed = true;
    graph.addBehaviors(
      [
        {
          type: 'collapse-expand',
          trigger: 'dblclick',
        },
      ],
      'default',
    );
    graph.on('afterrefreshlayout', () => {
      if (collapsed) {
        expect(parent.getModel().collapsed).toBe(true);
        expect(child.destroyed).toBe(true);
      } else {
        child = graph.findById('SubTreeNode1.1');
        expect(parent.getModel().collapsed).toBe(false);
        expect(child.get('model').x).not.toEqual(parent.get('model').x);
        expect(!!child.getModel().collapsed).toBe(false);
        expect(child.get('model').y).not.toEqual(parent.get('model').y);
      }
    });
    graph.emit('node:dblclick', { item: parent });
    timerOut(() => {
      collapsed = false;
      graph.emit('node:dblclick', { item: parent });
    }, 600);
  });
});

describe('update child', () => {
  const graph = new TreeGraph({
    container: div,
    width: 500,
    height: 500,
    animate: false,
    modes: {
      default: ['drag-canvas', 'drag-node'],
    },
    layout: {
      type: 'dendrogram',
      direction: 'LR', // H / V / LR / RL / TB / BT
      nodeSep: 50,
      rankSep: 100,
    },
  });

  const data = {
    isRoot: true,
    id: 'Root',
    children: [
      {
        id: 'SubTreeNode1',
      },
      {
        id: 'SubTreeNode3',
      },
    ],
  };
  graph.data(data);
  graph.render();

  it('updateChild & parent is not undefined', () => {
    const child = {
      id: 'SubTreeNode3.1',
      x: 150,
      y: 150,
      type: 'rect',
      children: [{ x: 250, y: 150, id: 'SubTreeNode3.1.1' }],
    };

    // 第一种情况，parent存在，添加的数据不存在
    graph.updateChild(child, 'SubTreeNode3');
    // 更新以后，SubTreeNode3 节点后会有子元素
    const subNode = graph.findById('SubTreeNode3');
    const children = subNode.get('children');
    expect(children).not.toBe(undefined);
    expect(children.length).toBe(1);

    const subNode3 = graph.findById('SubTreeNode3.1');
    const mode = subNode3.getModel();
    expect(mode.x).toBe(182);
    expect(mode.y).toBe(-24);
    expect(mode.type).toEqual('rect');
    expect(subNode3.get('currentShape')).toEqual('rect');
    expect(subNode3.get('children')).not.toBe(undefined);
    expect(subNode3.get('children').length).toBe(1);

    // 第二种情况，parent存在，添加的数据存在
    const treeGraphData = {
      id: 'SubTreeNode3.1',
      label: 'SubTreeNode3.1',
      x: 120,
      y: 156,
      type: 'circle',
    };
    graph.updateChild(treeGraphData, 'SubTreeNode3');

    const node = graph.findById('SubTreeNode3.1');
    const model1 = node.getModel();
    expect(model1.x).toBe(182);
    expect(model1.y).toBe(-24);
    expect(model1.type).toEqual('circle');
    expect(node.get('children').length).toBe(0);
  });

  it('updateChild & parent is undefined', () => {
    const child = {
      id: 'SubTreeNode3.1',
      x: 150,
      y: 150,
      type: 'rect',
      children: [{ x: 250, y: 150, id: 'SubTreeNode3.1.1' }],
    };

    // 更新子元素，parent不存在
    graph.updateChild(child);

    // 之前的数据全都被重置
    expect(graph.findById('Root')).toBe(undefined);
    expect(graph.findById('SubTreeNode3')).toBe(undefined);
    const node = graph.findById('SubTreeNode3.1');
    expect(node).not.toBe(undefined);
    expect(node.get('children')).not.toBe(undefined);
    expect(node.get('children').length).toBe(1);
    graph.destroy();
  });
});

describe('updateLayout, layout', () => {
  const graph = new TreeGraph({
    container: div,
    width: 500,
    height: 500,
    animate: false,
    modes: {
      default: ['drag-canvas', 'drag-node'],
    },
    layout: {
      type: 'dendrogram',
      direction: 'LR', // H / V / LR / RL / TB / BT
      nodeSep: 50,
      rankSep: 100,
    },
  });

  const data = {
    isRoot: true,
    id: 'Root',
    children: [
      {
        id: 'SubTreeNode1',
        children: [
          {
            id: '1.1',
          },
          {
            id: '1.2',
          },
        ],
      },
      {
        id: 'SubTreeNode3',
        children: [
          {
            id: '3.1',
          },
          {
            id: '3.2',
          },
        ],
      },
    ],
  };
  graph.data(data);
  graph.render();

  it('updateLayout', () => {
    graph.moveTo(100, 200);
    const item = graph.getNodes()[1];
    const model = item.getModel();
    const beforeChangePos = [model.x, model.y];
    graph.updateLayout({
      type: 'compactBox',
      direction: 'LR',
    });
    const afterChangePos = [model.x, model.y];
    expect(beforeChangePos[0]).not.toBe(afterChangePos[0]);
    expect(beforeChangePos[1]).not.toBe(afterChangePos[1]);

    // changeLayout will be discarded soon.
    graph.changeLayout({
      type: 'mindmap',
      direction: 'H',
    });
    const afterChangePos2 = [model.x, model.y];
    expect(afterChangePos[1]).not.toBe(afterChangePos2[1]);

    // updateLayout without layout
    graph.updateLayout(null);
    const afterChangePos3 = [model.x, model.y];
    expect(afterChangePos2[0]).toBe(afterChangePos3[0]);
    expect(afterChangePos2[1]).toBe(afterChangePos3[1]);
  });

  it('refreshLayout', () => {
    data.children.push({
      id: 'newSubTree',
      children: [],
    });
    graph.refreshLayout();
    expect(graph.getNodes().length).toBe(8);
    graph.refreshLayout(true);
    expect(graph.getNodes().length).toBe(8);
  });
});

describe('tree graph with animate', () => {
  const graph3 = new TreeGraph({
    container: div,
    width: 500,
    height: 500,
    animate: true,
    modes: {
      default: ['drag-canvas'],
    },
    layout: {
      type: 'dendrogram',
      direction: 'LR',
      nodeSep: 50,
      rankSep: 100,
    },
  });
  it('layout init', () => {
    const data2 = {
      isRoot: true,
      id: 'Root',
      children: [
        {
          id: 'SubTreeNode1',
          label: 'SubTreeNode1',
          children: [
            {
              id: 'SubTreeNode1.1',
            },
            {
              id: 'SubTreeNode1.2',
            },
          ],
        },
        {
          id: 'SubTreeNode2',
        },
      ],
    };
    graph3.data(data2);
    graph3.render();
    graph3.fitView();

    const layoutMethod = graph3.get('layoutMethod');

    expect(layoutMethod).not.toBe(undefined);
    expect(typeof layoutMethod).toEqual('function');

    expect(Object.keys(graph3.get('itemMap')).length).toEqual(9);

    const edge = graph3.findById('Root:SubTreeNode1');
    expect(edge).not.toBe(undefined);

    expect(edge.get('source')).toEqual(graph3.findById('Root'));
    expect(edge.get('target')).toEqual(graph3.findById('SubTreeNode1'));
    expect(graph3.save()).toEqual(data2);
  });
  it('changeData', () => {
    graph3.off();
    const data3 = {
      isRoot: true,
      id: 'Root',
      children: [
        {
          id: 'SubTreeNode1',
          label: 'SubTreeNode1',
          children: [
            {
              id: 'SubTreeNode1.1',
            },
            {
              id: 'SubTreeNode1.2',
            },
          ],
        },
        {
          id: 'SubTreeNode3',
        },
        {
          id: 'SubTreeNode4',
          children: [{ id: 'SubTreeNode4.1' }],
        },
      ],
    };

    graph3.on('afteranimate', () => {
      expect(Object.keys(graph3.get('itemMap')).length).toEqual(13);

      expect(graph3.findById('SubTreeNode2')).toBe(undefined);
      expect(graph3.findById('SubTreeNode3')).not.toBe(undefined);
      expect(graph3.findById('SubTreeNode4')).not.toBe(undefined);

      const edge = graph3.findById('SubTreeNode4:SubTreeNode4.1');

      expect(edge).not.toBe(undefined);
      expect(edge.get('source')).toEqual(graph3.findById('SubTreeNode4'));
      expect(edge.get('target')).toEqual(graph3.findById('SubTreeNode4.1'));
    });

    graph3.changeData(data3);

    expect(graph3.save()).toEqual(data3);
  });
  it('collapse & expand with parameter trigger=dblclick', (done) => {
    graph3.off();
    graph3.moveTo(100, 150);

    const parent = graph3.findById('SubTreeNode1');
    let child = graph3.findById('SubTreeNode1.1');

    let collapsed = undefined;
    graph3.on('afteranimate', () => {
      if (collapsed === undefined) return;
      if (collapsed) {
        expect(parent.getModel().collapsed).toBe(true);
        expect(child.destroyed).toBe(true);
      } else {
        child = graph3.findById('SubTreeNode1.1');
        expect(parent.getModel().collapsed).toBe(false);
        expect(child.get('model').x).not.toEqual(parent.get('model').x);
        expect(!!child.getModel().collapsed).toBe(false);
        expect(child.get('model').y).not.toEqual(parent.get('model').y);
        // done();
      }
    });
    graph3.addBehaviors(
      [
        {
          type: 'collapse-expand',
          trigger: 'dblclick',
        },
      ],
      'default',
    );
    timerOut(() => {
      graph3.emit('node:dblclick', { item: parent });
      collapsed = true;
    }, 600);

    timerOut(() => {
      collapsed = false;
      graph3.emit('node:dblclick', { item: parent });
      done();
    }, 1200);
  });
  it('collapse & expand', () => {
    graph3.off();

    const parent = graph3.findById('SubTreeNode1');
    let child = graph3.findById('SubTreeNode1.1');

    let collapsed = true;
    graph3.on('afteranimate', () => {
      if (collapsed) {
        expect(parent.getModel().collapsed).toBe(true);
        expect(child.destroyed).toBe(true);
      } else {
        child = graph3.findById('SubTreeNode1.1');
        expect(parent.getModel().collapsed).toBe(false);
        expect(child.get('model').x).not.toEqual(parent.get('model').x);
        expect(!!child.getModel().collapsed).toBe(false);
        expect(child.get('model').y).not.toEqual(parent.get('model').y);
      }
    });
    graph3.addBehaviors('collapse-expand', 'default');
    graph3.emit('node:click', { item: parent });

    timerOut(() => {
      collapsed = false;
      graph3.emit('node:click', { item: parent });
    }, 600);
  });

  // it('test', () => {
  //   const data = {
  //     isRoot: true,
  //     id: 'Root',
  //     children: [
  //       {
  //         id: 'SubTreeNode1',
  //         children: [
  //           {
  //             id: 'SubTreeNode1.1'
  //           },
  //           {
  //             id: 'SubTreeNode1.2'
  //           }
  //         ]
  //       },
  //       {
  //         id: 'SubTreeNode2'
  //       }
  //     ]
  //   };
  //   const graph2 = new TreeGraph({
  //     container: div,
  //     width: 500,
  //     height: 500,
  //     animate: false,
  //     modes: {
  //       default: [ 'drag-canvas', 'drag-node' ]
  //     },
  //     layout: {
  //       type: 'dendrogram',
  //       direction: 'LR', // H / V / LR / RL / TB / BT
  //       nodeSep: 50,
  //       rankSep: 100
  //     }
  //   });
  //   graph2.data(data);
  //   graph2.render();

  //   const pos = [0, 0];
  //   graph2.on('node:click', () => {
  //     pos[0] += 10;
  //     pos[1] += 10;
  //     graph2.moveTo(pos[0], pos[1]);
  //   });
  // });
});
