// 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 {renderHook} from "@testing-library/react";
import type {Connection} from "@xyflow/react";
import {
  ruleResult,
  type RuleResult,
  useHandleRules
} from "../../../../src/pages/VisProgPage/visualProgrammingUI/HandleRuleLogic.ts";
import useFlowStore from "../../../../src/pages/VisProgPage/visualProgrammingUI/VisProgStores.tsx";

describe('useHandleRules', () => {
  it('should register rules on mount and validate connection', () => {
    const rules = [() => ({ isSatisfied: true } as RuleResult)];

    const { result } = renderHook(() => useHandleRules('node1', 'h1', 'target', rules));

    // Confirm rules registered
    const storedRules = useFlowStore.getState().getTargetRules('node1', 'h1');
    expect(storedRules).toEqual(rules);

    // Validate a connection
    const connection = { source: 'node2', sourceHandle: 'h2', target: 'node1', targetHandle: 'h1' };
    const validation = result.current(connection);
    expect(validation).toEqual(ruleResult.satisfied);
  });

  it('should throw error if targetHandle missing', () => {
    const rules: any[] = [];
    const { result } = renderHook(() => useHandleRules('node1', 'h1', 'target', rules));

    expect(() =>
      result.current({ source: 'a', target: 'b', targetHandle: null, sourceHandle: null })
    ).toThrow('No target handle was provided');
  });
});

describe('useHandleRules with multiple failed rules', () => {
  it('should return the first failed rule message and consider connectionCount', () => {
    // Mock rules for the target handle
    const failingRules = [
      (_conn: any, ctx: any) => {
        if (ctx.connectionCount >= 1) {
          return { isSatisfied: false, message: 'Max connections reached' } as RuleResult;
        }
        return { isSatisfied: true } as RuleResult;
      },
      () => ({ isSatisfied: false, message: 'Other rule failed' } as RuleResult),
      () => ({ isSatisfied: true } as RuleResult),
    ];

    // Register rules for the target handle
    useFlowStore.getState().registerRules('targetNode', 'targetHandle', failingRules);

    // Add one existing edge to simulate connectionCount
    useFlowStore.setState({
      edges: [
        {
          id: 'edge-1',
          source: 'sourceNode',
          sourceHandle: 'sourceHandle',
          target: 'targetNode',
          targetHandle: 'targetHandle',
        },
      ],
    });

    // Create hook for a source node handle
    const rulesForSource = [
      (_c: Connection) => ({ isSatisfied: true } as RuleResult)
    ];
    const { result } = renderHook(() =>
      useHandleRules('sourceNode', 'sourceHandle', 'source', rulesForSource)
    );

    const connection = {
      source: 'sourceNode',
      sourceHandle: 'sourceHandle',
      target: 'targetNode',
      targetHandle: 'targetHandle',
    };

    const validation = result.current(connection);

    // Should fail with first failing rule message
    expect(validation).toEqual(ruleResult.notSatisfied('Max connections reached'));
  });
});