import useFlowStore from '../../../../../src/pages/VisProgPage/visualProgrammingUI/VisProgStores';
import type { PhaseNodeData } from "../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/PhaseNode";
import { getByTestId, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import VisProgPage from '../../../../../src/pages/VisProgPage/VisProg';


class ResizeObserver {
  observe() {}
  unobserve() {}
  disconnect() {}
}
window.ResizeObserver = ResizeObserver;

jest.mock('@neodrag/react', () => ({
  useDraggable: (ref: React.RefObject<HTMLElement>, options: any) => {
    // We access the real useEffect from React to attach a listener
    // This bridges the gap between the test's userEvent and the component's logic
    const { useEffect } = jest.requireActual('react');
    
    useEffect(() => {
      const element = ref.current;
      if (!element) return;

      // When the test fires a "pointerup" (end of click/drag), 
      // we manually trigger the library's onDragEnd callback.
      const handlePointerUp = (e: PointerEvent) => {
        if (options.onDragEnd) {
          options.onDragEnd({ event: e });
        }
      };

      element.addEventListener('pointerup', handlePointerUp as EventListener);
      return () => {
        element.removeEventListener('pointerup', handlePointerUp as EventListener);
      };
    }, [ref, options]);
  },
}));

describe('PhaseNode', () => {
  it('each created phase gets its own children array, not the same reference ', async () => {
    const user = userEvent.setup();

    const { container } = render(<VisProgPage />);

    // --- Mock ReactFlow bounding box ---
    // Your DndToolbar checks these values:
    const flowEl = container.querySelector('.react-flow');
    jest.spyOn(flowEl!, 'getBoundingClientRect').mockReturnValue({
      left: 0,
      right: 800,
      top: 0,
      bottom: 600,
      width: 800,
      height: 600,
      x: 0,
      y: 0,
      toJSON: () => {},
    });
    
    // Find the draggable norm node in the toolbar
    const phaseButton = getByTestId(container, 'draggable-phase')
    
    // Simulate dropping phase down in graph (twice)
    for (let i = 0; i < 2; i++) {
    await user.pointer([
      // touch the screen at element1
      {keys: '[TouchA>]', target: phaseButton},
      // move the touch pointer to element2
      {pointerName: 'TouchA', coords: {x: 300, y: 250}},
      // release the touch pointer at the last position (element2)
      {keys: '[/TouchA]'},
    ]);
    }

    // Find nodes
    const nodes = useFlowStore.getState().nodes;
    const phaseNodes = nodes.filter((x) => x.type === 'phase');
    const p1 = phaseNodes[0];
    const p2 = phaseNodes[1];


    // expect same value, not same reference
    expect(p1.data.children).not.toBe(p2.data.children);
    expect(p1.data.children).toEqual(p2.data.children);

    // Add nodes to children
    const p1_data = p1.data as PhaseNodeData;
    const p2_data = p2.data as PhaseNodeData;
    p1_data.children.push("norm-1");
    p2_data.children.push("norm-2");
    p2_data.children.push("goal-1");

    // check that after adding, its not the same reference, and its not the same children
    expect(p1.data.children).not.toBe(p2.data.children);
    expect(p1.data.children).not.toEqual(p2.data.children);
    
    // expect them to have the correct length.
    expect(p1_data.children.length == 1);
    expect(p2_data.children.length == 2);
  });
});