import flowDb from '../flowDb';
import flow from './flow';
import filter from 'lodash/filter';
import { setConfig } from '../../../config';

setConfig({
  securityLevel: 'strict',
});

describe('when parsing subgraphs', function () {
  beforeEach(function () {
    flow.parser.yy = flowDb;
    flow.parser.yy.clear();
    flow.parser.yy.setGen('gen-2');
  });
  it('should handle subgraph with tab indentation', function () {
    const res = flow.parser.parse('graph TB\nsubgraph One\n\ta1-->a2\nend');
    const subgraphs = flow.parser.yy.getSubGraphs();
    expect(subgraphs.length).toBe(1);
    const subgraph = subgraphs[0];

    expect(subgraph.nodes.length).toBe(2);
    expect(subgraph.nodes[0]).toBe('a2');
    expect(subgraph.nodes[1]).toBe('a1');
    expect(subgraph.title).toBe('One');
    expect(subgraph.id).toBe('One');
  });
  it('should handle subgraph with chaining nodes indentation', function () {
    const res = flow.parser.parse('graph TB\nsubgraph One\n\ta1-->a2-->a3\nend');
    const subgraphs = flow.parser.yy.getSubGraphs();
    expect(subgraphs.length).toBe(1);
    const subgraph = subgraphs[0];
    expect(subgraph.nodes.length).toBe(3);
    expect(subgraph.nodes[0]).toBe('a3');
    expect(subgraph.nodes[1]).toBe('a2');
    expect(subgraph.nodes[2]).toBe('a1');
    expect(subgraph.title).toBe('One');
    expect(subgraph.id).toBe('One');
  });

  it('should handle subgraph with multiple words in title', function () {
    const res = flow.parser.parse('graph TB\nsubgraph "Some Title"\n\ta1-->a2\nend');
    const subgraphs = flow.parser.yy.getSubGraphs();
    expect(subgraphs.length).toBe(1);
    const subgraph = subgraphs[0];
    expect(subgraph.nodes.length).toBe(2);
    expect(subgraph.nodes[0]).toBe('a2');
    expect(subgraph.nodes[1]).toBe('a1');
    expect(subgraph.title).toBe('Some Title');
    expect(subgraph.id).toBe('subGraph0');
  });

  it('should handle subgraph with id and title notation', function () {
    const res = flow.parser.parse('graph TB\nsubgraph some-id[Some Title]\n\ta1-->a2\nend');
    const subgraphs = flow.parser.yy.getSubGraphs();
    expect(subgraphs.length).toBe(1);
    const subgraph = subgraphs[0];
    expect(subgraph.nodes.length).toBe(2);
    expect(subgraph.nodes[0]).toBe('a2');
    expect(subgraph.nodes[1]).toBe('a1');
    expect(subgraph.title).toBe('Some Title');
    expect(subgraph.id).toBe('some-id');
  });

  it.skip('should handle subgraph without id and space in title', function () {
    const res = flow.parser.parse('graph TB\nsubgraph Some Title\n\ta1-->a2\nend');
    const subgraphs = flow.parser.yy.getSubGraphs();
    expect(subgraphs.length).toBe(1);
    const subgraph = subgraphs[0];
    expect(subgraph.nodes.length).toBe(2);
    expect(subgraph.nodes[0]).toBe('a1');
    expect(subgraph.nodes[1]).toBe('a2');
    expect(subgraph.title).toBe('Some Title');
    expect(subgraph.id).toBe('some-id');
  });

  it('should handle subgraph id starting with a number', function () {
    const res = flow.parser.parse(`graph TD
    A[Christmas] -->|Get money| B(Go shopping)
    subgraph 1test
    A
    end`);

    const subgraphs = flow.parser.yy.getSubGraphs();
    expect(subgraphs.length).toBe(1);
    const subgraph = subgraphs[0];
    expect(subgraph.nodes.length).toBe(1);
    expect(subgraph.nodes[0]).toBe('A');
    expect(subgraph.id).toBe('1test');
  });

  it('should handle subgraphs1', function () {
    const res = flow.parser.parse('graph TD;A-->B;subgraph myTitle;c-->d;end;');

    const vert = flow.parser.yy.getVertices();
    const edges = flow.parser.yy.getEdges();

    expect(edges[0].type).toBe('arrow_point');
  });
  it('should handle subgraphs with title in quotes', function () {
    const res = flow.parser.parse('graph TD;A-->B;subgraph "title in quotes";c-->d;end;');

    const vert = flow.parser.yy.getVertices();
    const edges = flow.parser.yy.getEdges();

    const subgraphs = flow.parser.yy.getSubGraphs();
    expect(subgraphs.length).toBe(1);
    const subgraph = subgraphs[0];

    expect(subgraph.title).toBe('title in quotes');

    expect(edges[0].type).toBe('arrow_point');
  });
  it('should handle subgraphs in old style that was broken', function () {
    const res = flow.parser.parse('graph TD;A-->B;subgraph old style that is broken;c-->d;end;');

    const vert = flow.parser.yy.getVertices();
    const edges = flow.parser.yy.getEdges();

    const subgraphs = flow.parser.yy.getSubGraphs();
    expect(subgraphs.length).toBe(1);
    const subgraph = subgraphs[0];

    expect(subgraph.title).toBe('old style that is broken');

    expect(edges[0].type).toBe('arrow_point');
  });
  it('should handle subgraphs with dashes in the title', function () {
    const res = flow.parser.parse('graph TD;A-->B;subgraph a-b-c;c-->d;end;');

    const vert = flow.parser.yy.getVertices();
    const edges = flow.parser.yy.getEdges();

    const subgraphs = flow.parser.yy.getSubGraphs();
    expect(subgraphs.length).toBe(1);
    const subgraph = subgraphs[0];

    expect(subgraph.title).toBe('a-b-c');

    expect(edges[0].type).toBe('arrow_point');
  });
  it('should handle subgraphs with id and title in brackets', function () {
    const res = flow.parser.parse('graph TD;A-->B;subgraph uid1[text of doom];c-->d;end;');

    const vert = flow.parser.yy.getVertices();
    const edges = flow.parser.yy.getEdges();

    const subgraphs = flow.parser.yy.getSubGraphs();
    expect(subgraphs.length).toBe(1);
    const subgraph = subgraphs[0];

    expect(subgraph.title).toBe('text of doom');
    expect(subgraph.id).toBe('uid1');

    expect(edges[0].type).toBe('arrow_point');
  });
  it('should handle subgraphs with id and title in brackets and quotes', function () {
    const res = flow.parser.parse('graph TD;A-->B;subgraph uid2["text of doom"];c-->d;end;');

    const vert = flow.parser.yy.getVertices();
    const edges = flow.parser.yy.getEdges();

    const subgraphs = flow.parser.yy.getSubGraphs();
    expect(subgraphs.length).toBe(1);
    const subgraph = subgraphs[0];

    expect(subgraph.title).toBe('text of doom');
    expect(subgraph.id).toBe('uid2');

    expect(edges[0].type).toBe('arrow_point');
  });
  it('should handle subgraphs with id and title in brackets without spaces', function () {
    const res = flow.parser.parse('graph TD;A-->B;subgraph uid2[textofdoom];c-->d;end;');

    const vert = flow.parser.yy.getVertices();
    const edges = flow.parser.yy.getEdges();

    const subgraphs = flow.parser.yy.getSubGraphs();
    expect(subgraphs.length).toBe(1);
    const subgraph = subgraphs[0];

    expect(subgraph.title).toBe('textofdoom');
    expect(subgraph.id).toBe('uid2');

    expect(edges[0].type).toBe('arrow_point');
  });

  it('should handle subgraphs2', function () {
    const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\n\n c-->d \nend\n');

    const vert = flow.parser.yy.getVertices();
    const edges = flow.parser.yy.getEdges();

    expect(edges[0].type).toBe('arrow_point');
  });

  it('should handle subgraphs3', function () {
    const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle   \n\n    c-->d \nend\n');

    const vert = flow.parser.yy.getVertices();
    const edges = flow.parser.yy.getEdges();

    expect(edges[0].type).toBe('arrow_point');
  });

  it('should handle nested subgraphs', function () {
    const str =
      'graph TD\n' +
      'A-->B\n' +
      'subgraph myTitle\n\n' +
      ' c-->d \n\n' +
      ' subgraph inner\n\n   e-->f \n end \n\n' +
      ' subgraph inner\n\n   h-->i \n end \n\n' +
      'end\n';
    const res = flow.parser.parse(str);
  });

  it('should handle subgraphs4', function () {
    const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\nc-->d\nend;');

    const vert = flow.parser.yy.getVertices();
    const edges = flow.parser.yy.getEdges();

    expect(edges[0].type).toBe('arrow_point');
  });

  it('should handle subgraphs5', function () {
    const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\nc-- text -->d\nd-->e\n end;');

    const vert = flow.parser.yy.getVertices();
    const edges = flow.parser.yy.getEdges();

    expect(edges[0].type).toBe('arrow_point');
  });
  it('should handle subgraphs with multi node statements in it', function () {
    const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\na & b --> c & e\n end;');

    const vert = flow.parser.yy.getVertices();
    const edges = flow.parser.yy.getEdges();

    expect(edges[0].type).toBe('arrow_point');
  });
  it('should handle nested subgraphs 1', function () {
    const res = flow.parser.parse(`flowchart TB
    subgraph A
    b-->B
    a
    end
    a-->c
    subgraph B
      c
    end`);

    const subgraphs = flow.parser.yy.getSubGraphs();
    expect(subgraphs.length).toBe(2);

    const subgraphA = filter(subgraphs, (o) => o.id === 'A')[0];
    const subgraphB = filter(subgraphs, (o) => o.id === 'B')[0];

    expect(subgraphB.nodes[0]).toBe('c');
    expect(subgraphA.nodes).toContain('B');
    expect(subgraphA.nodes).toContain('b');
    expect(subgraphA.nodes).toContain('a');
    expect(subgraphA.nodes).not.toContain('c');
  });
  it('should handle nested subgraphs 2', function () {
    const res = flow.parser.parse(`flowchart TB
    b-->B
    a-->c
    subgraph B
      c
    end
    subgraph A
        a
        b
        B
    end`);

    const subgraphs = flow.parser.yy.getSubGraphs();
    expect(subgraphs.length).toBe(2);

    const subgraphA = filter(subgraphs, (o) => o.id === 'A')[0];
    const subgraphB = filter(subgraphs, (o) => o.id === 'B')[0];

    expect(subgraphB.nodes[0]).toBe('c');
    expect(subgraphA.nodes).toContain('B');
    expect(subgraphA.nodes).toContain('b');
    expect(subgraphA.nodes).toContain('a');
    expect(subgraphA.nodes).not.toContain('c');
  });
  it('should handle nested subgraphs 3', function () {
    const res = flow.parser.parse(`flowchart TB
    subgraph B
      c
    end
    a-->c
    subgraph A
      b-->B
      a
    end`);

    const subgraphs = flow.parser.yy.getSubGraphs();
    expect(subgraphs.length).toBe(2);

    const subgraphA = filter(subgraphs, (o) => o.id === 'A')[0];
    const subgraphB = filter(subgraphs, (o) => o.id === 'B')[0];
    expect(subgraphB.nodes[0]).toBe('c');
    expect(subgraphA.nodes).toContain('B');
    expect(subgraphA.nodes).toContain('b');
    expect(subgraphA.nodes).toContain('a');
    expect(subgraphA.nodes).not.toContain('c');
  });
});
