import { WorkflowDefinition } from '../../src/core/workflow';
import { StepType, IWorkflowContext } from '../../src/types';
import { describe, test, expect, beforeEach, jest } from '@jest/globals';

describe('WorkflowDefinition', () => {
  let workflow: WorkflowDefinition;
  
  beforeEach(() => {
    workflow = new WorkflowDefinition('test-workflow', 'Test Workflow', 'A workflow for testing');
  });
  
  describe('constructor', () => {
    test('should create a workflow with provided id, name and description', () => {
      expect(workflow.id).toBe('test-workflow');
      expect(workflow.name).toBe('Test Workflow');
      expect(workflow.description).toBe('A workflow for testing');
    });
    
    test('should generate a UUID if id is not provided', () => {
      const workflowWithoutId = new WorkflowDefinition('');
      expect(workflowWithoutId.id).toBeTruthy();
      expect(workflowWithoutId.id.length).toBeGreaterThan(0);
    });
  });
  
  describe('addStep', () => {
    test('should add a task step', () => {
      workflow.addStep({
        id: 'step1',
        nodeId: 'someNodeId'
      });
      
      const step = workflow.getStep('step1');
      expect(step).toBeDefined();
      expect(step?.type).toBe(StepType.TASK);
      expect(step?.id).toBe('step1');
      expect(step?.getNodeId()).toBe('someNodeId');
    });
    
    test('should set the first step as start step', () => {
      workflow.addStep({
        id: 'step1',
        nodeId: 'someNodeId'
      });
      
      expect(workflow.getStartStepId()).toBe('step1');
    });
    
    test('should throw if step id already exists', () => {
      workflow.addStep({
        id: 'step1',
        nodeId: 'someNodeId'
      });
      
      expect(() => {
        workflow.addStep({
          id: 'step1',
          nodeId: 'anotherNodeId'
        });
      }).toThrow();
    });
  });
  
  describe('addConditionStep', () => {
    test('should add a condition step', () => {
      const condition = function(context: IWorkflowContext) { return true; };
      
      workflow.addConditionStep({
        id: 'condition1',
        condition,
        branches: {
          'true': 'trueStep',
          'false': 'falseStep'
        }
      });
      
      const step = workflow.getStep('condition1');
      expect(step).toBeDefined();
      expect(step?.type).toBe(StepType.CONDITION);
      expect(step?.id).toBe('condition1');
    });
  });
  
  describe('setStartStep', () => {
    test('should set a specific step as start step', () => {
      workflow.addStep({
        id: 'step1',
        nodeId: 'nodeId1'
      });
      
      workflow.addStep({
        id: 'step2',
        nodeId: 'nodeId2'
      });
      
      workflow.setStartStep('step2');
      
      expect(workflow.getStartStepId()).toBe('step2');
    });
    
    test('should throw if step does not exist', () => {
      expect(() => {
        workflow.setStartStep('nonExistentStep');
      }).toThrow();
    });
  });
  
  describe('validate', () => {
    test('should return true for a valid workflow', () => {
      workflow.addStep({
        id: 'step1',
        nodeId: 'nodeId1'
      });
      
      expect(workflow.validate()).toBe(true);
    });
    
    test('should return false if no steps are defined', () => {
      // Empty workflow with no steps
      expect(workflow.validate()).toBe(false);
    });
  });
}); 