// 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 type {PhaseNode} from "../../src/pages/VisProgPage/visualProgrammingUI/nodes/PhaseNode.tsx";
import orderPhaseNodeArray from "../../src/utils/orderPhaseNodes.ts";

function createPhaseNode(
  id: string,
  isFirst: boolean = false,
  nextPhaseId: string | null = null
): PhaseNode {
  return {
    id: id,
    type: 'phase',
    position: { x: 0, y: 0 },
    data: {
      label: 'Phase',
      droppable: true,
      children: [],
      hasReduce: true,
      nextPhaseId: nextPhaseId,
      isFirstPhase: isFirst,
    },
  }
}

describe("orderPhaseNodes", () => {
  test.each([
    {
      testCase: {
        testName: "Throws correct error when there is no first phase (empty input array)",
        input: [],
        expected: "No phaseNode with isFirstObject = true found"
      }
    },{
      testCase: {
        testName: "Throws correct error when there is no first phase",
        input: [
          createPhaseNode("phase-1", false, "phase-2"),
          createPhaseNode("phase-2", false, "phase-3"),
          createPhaseNode("phase-3", false, "end")
        ],
        expected: "No phaseNode with isFirstObject = true found"
      }
    },{
      testCase: {
        testName: "Throws correct error when the program doesn't lead to an end node (missing phase-phase connection)",
        input: [
          createPhaseNode("phase-1", true, "phase-2"),
          createPhaseNode("phase-2", false, null),
          createPhaseNode("phase-3", false, "end")
        ],
        expected: "Incomplete phase sequence, program does not reach the end node"
      }
    },{
      testCase: {
        testName: "Throws correct error when the program doesn't lead to an end node (missing phase-end connection)",
        input: [
          createPhaseNode("phase-1", true, "phase-2"),
          createPhaseNode("phase-2", false, "phase-3"),
          createPhaseNode("phase-3", false, null)
        ],
        expected: "Incomplete phase sequence, program does not reach the end node"
      }
    },{
      testCase: {
        testName: "Throws correct error when the program leads to a non-existent phase",
        input: [
          createPhaseNode("phase-1", true, "phase-2"),
          createPhaseNode("phase-2", false, "phase-3"),
          createPhaseNode("phase-3", false, "phase-4")
        ],
        expected: "Incomplete phase sequence, phaseNode with id \"phase-4\" not found"
      }
    }
  ])(`Error Handling: $testCase.testName`, ({testCase}) => {
    expect(() => { orderPhaseNodeArray(testCase.input) }).toThrow(testCase.expected);
  })
  test.each([
    {
      testCase: {
        testName: "Already correctly ordered phases stay ordered",
        input: [
          createPhaseNode("phase-1", true, "phase-2"),
          createPhaseNode("phase-2", false, "phase-3"),
          createPhaseNode("phase-3", false, "end")
        ],
        expected: [
          createPhaseNode("phase-1", true, "phase-2"),
          createPhaseNode("phase-2", false, "phase-3"),
          createPhaseNode("phase-3", false, "end")
        ]
      }
    },{
      testCase: {
        testName: "Incorrectly ordered phases get ordered correctly",
        input: [
          createPhaseNode("phase-3", false, "end"),
          createPhaseNode("phase-1", true, "phase-2"),
          createPhaseNode("phase-2", false, "phase-3"),
        ],
        expected: [
          createPhaseNode("phase-1", true, "phase-2"),
          createPhaseNode("phase-2", false, "phase-3"),
          createPhaseNode("phase-3", false, "end")
        ]
      }
    }
  ])(`Functional: $testCase.testName`, ({testCase}) => {
    const output = orderPhaseNodeArray(testCase.input);
    expect(output).toEqual(testCase.expected);
  })
})