// This program has been developed by students from the bachelor Computer Science at Utrecht
// University within the Software Project course.
// © Copyright Utrecht University (Department of Information and Computing Sciences)
import {ruleResult} from "../../../../src/pages/VisProgPage/visualProgrammingUI/HandleRuleLogic.ts";
import {
  allowOnlyConnectionsFromType,
  allowOnlyConnectionsFromHandle, noSelfConnections
} from "../../../../src/pages/VisProgPage/visualProgrammingUI/HandleRules.ts";
import useFlowStore from "../../../../src/pages/VisProgPage/visualProgrammingUI/VisProgStores.tsx";

beforeEach(() => {
  useFlowStore.setState({
    nodes: [
      { id: 'nodeA', type: 'typeA', position: { x: 0, y: 0 }, data: {} },
      { id: 'nodeB', type: 'typeB', position: { x: 0, y: 0 }, data: {} },
    ],
  });
});

describe('allowOnlyConnectionsFromType', () => {
  it('should allow connection from allowed node type', () => {
    const rule = allowOnlyConnectionsFromType(['typeA']);
    const connection = { source: 'nodeA', sourceHandle: 'h1', target: 'nodeB', targetHandle: 'h2' };
    const context = { connectionCount: 0, source: { id: 'nodeA', handleId: 'h1' }, target: { id: 'nodeB', handleId: 'h2' } };

    const result = rule(connection, context);
    expect(result).toEqual(ruleResult.satisfied);
  });

  it('should not allow connection from disallowed node type', () => {
    const rule = allowOnlyConnectionsFromType(['typeA']);
    const connection = { source: 'nodeB', sourceHandle: 'h1', target: 'nodeA', targetHandle: 'h2' };
    const context = { connectionCount: 0, source: { id: 'nodeB', handleId: 'h1' }, target: { id: 'nodeA', handleId: 'h2' } };

    const result = rule(connection, context);
    expect(result).toEqual(ruleResult.notSatisfied("the target doesn't allow connections from nodes with type: typeB"));
  });
});
describe('allowOnlyConnectionsFromHandle', () => {
  it('should allow connection from node with correct type and handle', () => {
    const rule = allowOnlyConnectionsFromHandle([{ nodeType: 'typeA', handleId: 'h1' }]);
    const connection = { source: 'nodeA', sourceHandle: 'h1', target: 'nodeB', targetHandle: 'h2' };
    const context = { connectionCount: 0, source: { id: 'nodeA', handleId: 'h1' }, target: { id: 'nodeB', handleId: 'h2' } };

    const result = rule(connection, context);
    expect(result).toEqual(ruleResult.satisfied);
  });

  it('should not allow connection from node with wrong handle', () => {
    const rule = allowOnlyConnectionsFromHandle([{ nodeType: 'typeA', handleId: 'h1' }]);
    const connection = { source: 'nodeA', sourceHandle: 'wrongHandle', target: 'nodeB', targetHandle: 'h2' };
    const context = { connectionCount: 0, source: { id: 'nodeA', handleId: 'wrongHandle' }, target: { id: 'nodeB', handleId: 'h2' } };

    const result = rule(connection, context);
    expect(result).toEqual(ruleResult.notSatisfied("the target doesn't allow connections from nodes with type: typeA"));
  });

  it('should not allow connection from node with wrong type', () => {
    const rule = allowOnlyConnectionsFromHandle([{ nodeType: 'typeA', handleId: 'h1' }]);
    const connection = { source: 'nodeB', sourceHandle: 'h1', target: 'nodeA', targetHandle: 'h2' };
    const context = { connectionCount: 0, source: { id: 'nodeB', handleId: 'h1' }, target: { id: 'nodeA', handleId: 'h2' } };

    const result = rule(connection, context);
    expect(result).toEqual(ruleResult.notSatisfied("the target doesn't allow connections from nodes with type: typeB"));
  });
});

describe('noSelfConnections', () => {
  it('should allow connection from node with other type and handle', () => {
    const rule = noSelfConnections;
    const connection = { source: 'nodeA', sourceHandle: 'h1', target: 'nodeB', targetHandle: 'h2' };
    const context = { connectionCount: 0, source: { id: 'nodeA', handleId: 'h1' }, target: { id: 'nodeB', handleId: 'h2' } };

    const result = rule(connection, context);
    expect(result).toEqual(ruleResult.satisfied);
  });

  it('should not allow connection from other handle on same node', () => {
    const rule = noSelfConnections;
    const connection = { source: 'nodeA', sourceHandle: 'h1', target: 'nodeA', targetHandle: 'h2' };
    const context = { connectionCount: 0, source: { id: 'nodeA', handleId: 'h1' }, target: { id: 'nodeB', handleId: 'h2' } };

    const result = rule(connection, context);
    expect(result).toEqual(ruleResult.notSatisfied("nodes are not allowed to connect to themselves"));
  });

});