import { describe, it, expect, jest, beforeEach } from '@jest/globals';
import type {Node, Edge} from '@xyflow/react';
import * as FlowStore from '../../../../../src/pages/VisProgPage/visualProgrammingUI/VisProgStores.tsx';
import {
  type InferredBelief,
  InferredBeliefConnectionTarget,
  InferredBeliefDisconnectionTarget,
  InferredBeliefReduce,
} from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/InferredBeliefNode.tsx';

// helper functions
function inferredNode(overrides = {}): Node {
  return {
    id: 'i1',
    type: 'inferred_belief',
    position: {x: 0, y: 0},
    data: {
      inferredBelief: {
        left: undefined,
        operator: true,
        right: undefined,
      },
      ...overrides,
    },
  } as Node;
}

describe('InferredBelief connection logic', () => {
  let getStateSpy: ReturnType<typeof jest.spyOn>;

  beforeEach(() => {
    jest.clearAllMocks();
    getStateSpy = jest.spyOn(FlowStore.default, 'getState');
  });

  it('sets left belief when connected on beliefLeft handle', () => {
    const node = inferredNode();

    getStateSpy.mockReturnValue({
      nodes: [{ id: 'b1', type: 'basic_belief' }],
      edges: [
        {
          source: 'b1',
          target: 'i1',
          targetHandle: 'beliefLeft',
        } as Edge,
      ],
    } as any);

    InferredBeliefConnectionTarget(node, 'b1');

    expect((node.data.inferredBelief as InferredBelief).left).toBe('b1');
    expect((node.data.inferredBelief as InferredBelief).right).toBeUndefined();
  });

  it('sets right belief when connected on beliefRight handle', () => {
    const node = inferredNode();

    getStateSpy.mockReturnValue({
      nodes: [{ id: 'b2', type: 'basic_belief' }],
      edges: [
        {
          source: 'b2',
          target: 'i1',
          targetHandle: 'beliefRight',
        } as Edge,
      ],
    } as any);

    InferredBeliefConnectionTarget(node, 'b2');

    expect((node.data.inferredBelief as InferredBelief).right).toBe('b2');
  });

  it('ignores connections from unsupported node types', () => {
    const node = inferredNode();

    getStateSpy.mockReturnValue({
      nodes: [{ id: 'x', type: 'norm' }],
      edges: [],
    } as any);

    InferredBeliefConnectionTarget(node, 'x');

    expect((node.data.inferredBelief as InferredBelief).left).toBeUndefined();
    expect((node.data.inferredBelief as InferredBelief).right).toBeUndefined();
  });

  it('clears left or right belief on disconnection', () => {
    const node = inferredNode({
      inferredBelief: { left: 'a', right: 'b', operator: true },
    });

    InferredBeliefDisconnectionTarget(node, 'a');
    expect((node.data.inferredBelief as InferredBelief).left).toBeUndefined();

    InferredBeliefDisconnectionTarget(node, 'b');
    expect((node.data.inferredBelief as InferredBelief).right).toBeUndefined();
  });
});

describe('InferredBeliefReduce', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  it('throws if left belief is missing', () => {
    const node = inferredNode({
      inferredBelief: { left: 'l', right: 'r', operator: true },
    });

    expect(() =>
      InferredBeliefReduce(node, [{ id: 'r' } as Node])
    ).toThrow('No Left belief found');
  });

  it('throws if right belief is missing', () => {
    const node = inferredNode({
      inferredBelief: { left: 'l', right: 'r', operator: true },
    });

    expect(() =>
      InferredBeliefReduce(node, [{ id: 'l' } as Node])
    ).toThrow('No Right Belief found');
  });

});


