import { describe, it, expect } from 'vitest';
import { StepTransitionValidator } from '../../../../packages/domain/services/StepTransitionValidator';
import { StepId } from '../../../../packages/domain/value-objects/StepId';
import { SessionState } from '../../../../packages/domain/value-objects/SessionState';

describe('StepTransitionValidator Service', () => {
  describe('canTransition', () => {
    it('should allow sequential forward transition', () => {
      const currentStep = StepId.create(1);
      const nextStep = StepId.create(2);
      const state = SessionState.create('IN_PROGRESS');

      const result = StepTransitionValidator.canTransition(currentStep, nextStep, state);

      expect(result.isValid).toBe(true);
      expect(result.error).toBeUndefined();
    });

    it('should reject transition when not IN_PROGRESS', () => {
      const currentStep = StepId.create(1);
      const nextStep = StepId.create(2);
      const state = SessionState.create('PENDING');

      const result = StepTransitionValidator.canTransition(currentStep, nextStep, state);

      expect(result.isValid).toBe(false);
      expect(result.error).toBe('Session must be in progress to transition steps');
    });

    it('should reject skipping steps', () => {
      const currentStep = StepId.create(1);
      const nextStep = StepId.create(3);
      const state = SessionState.create('IN_PROGRESS');

      const result = StepTransitionValidator.canTransition(currentStep, nextStep, state);

      expect(result.isValid).toBe(false);
      expect(result.error).toBe('Cannot skip steps - must progress sequentially');
    });

    it('should reject backward transitions', () => {
      const currentStep = StepId.create(5);
      const nextStep = StepId.create(4);
      const state = SessionState.create('IN_PROGRESS');

      const result = StepTransitionValidator.canTransition(currentStep, nextStep, state);

      expect(result.isValid).toBe(false);
      expect(result.error).toBe('Cannot move backward - steps must progress forward only');
    });

    it('should reject same step transition', () => {
      const currentStep = StepId.create(5);
      const nextStep = StepId.create(5);
      const state = SessionState.create('IN_PROGRESS');

      const result = StepTransitionValidator.canTransition(currentStep, nextStep, state);

      expect(result.isValid).toBe(false);
      expect(result.error).toBe('Already at this step');
    });

    it('should allow transition through modal steps', () => {
      const currentStep = StepId.create(5);
      const nextStep = StepId.create(6);
      const state = SessionState.create('IN_PROGRESS');

      const result = StepTransitionValidator.canTransition(currentStep, nextStep, state);

      expect(result.isValid).toBe(true);
    });

    it('should allow transition from modal step to next', () => {
      const currentStep = StepId.create(6);
      const nextStep = StepId.create(7);
      const state = SessionState.create('IN_PROGRESS');

      const result = StepTransitionValidator.canTransition(currentStep, nextStep, state);

      expect(result.isValid).toBe(true);
    });
  });

  describe('validateModalStepTransition', () => {
    it('should allow entering modal step 6', () => {
      const currentStep = StepId.create(5);
      const nextStep = StepId.create(6);

      const result = StepTransitionValidator.validateModalStepTransition(currentStep, nextStep);

      expect(result.isValid).toBe(true);
    });

    it('should allow entering modal step 9', () => {
      const currentStep = StepId.create(8);
      const nextStep = StepId.create(9);

      const result = StepTransitionValidator.validateModalStepTransition(currentStep, nextStep);

      expect(result.isValid).toBe(true);
    });

    it('should allow entering modal step 12', () => {
      const currentStep = StepId.create(11);
      const nextStep = StepId.create(12);

      const result = StepTransitionValidator.validateModalStepTransition(currentStep, nextStep);

      expect(result.isValid).toBe(true);
    });

    it('should allow exiting modal step 6', () => {
      const currentStep = StepId.create(6);
      const nextStep = StepId.create(7);

      const result = StepTransitionValidator.validateModalStepTransition(currentStep, nextStep);

      expect(result.isValid).toBe(true);
    });

    it('should allow non-modal transitions', () => {
      const currentStep = StepId.create(1);
      const nextStep = StepId.create(2);

      const result = StepTransitionValidator.validateModalStepTransition(currentStep, nextStep);

      expect(result.isValid).toBe(true);
    });
  });

  describe('shouldStopAtStep18', () => {
    it('should return true when transitioning to step 18', () => {
      const nextStep = StepId.create(18);

      const shouldStop = StepTransitionValidator.shouldStopAtStep18(nextStep);

      expect(shouldStop).toBe(true);
    });

    it('should return false for steps before 18', () => {
      const nextStep = StepId.create(17);

      const shouldStop = StepTransitionValidator.shouldStopAtStep18(nextStep);

      expect(shouldStop).toBe(false);
    });

    it('should return false for early steps', () => {
      const nextStep = StepId.create(1);

      const shouldStop = StepTransitionValidator.shouldStopAtStep18(nextStep);

      expect(shouldStop).toBe(false);
    });
  });

  describe('getStepDescription', () => {
    it('should return description for step 1', () => {
      const step = StepId.create(1);

      const description = StepTransitionValidator.getStepDescription(step);

      expect(description).toBe('Navigate to Hosted Racing page');
    });

    it('should return description for step 6 (modal)', () => {
      const step = StepId.create(6);

      const description = StepTransitionValidator.getStepDescription(step);

      expect(description).toBe('Add Admin (Modal)');
    });

    it('should return description for step 18 (final)', () => {
      const step = StepId.create(18);

      const description = StepTransitionValidator.getStepDescription(step);

      expect(description).toBe('Track Conditions (STOP - Manual Submit Required)');
    });

    it('should return descriptions for all modal steps', () => {
      const modalSteps = [6, 9, 12];

      modalSteps.forEach(stepNum => {
        const step = StepId.create(stepNum);
        const description = StepTransitionValidator.getStepDescription(step);
        expect(description).toContain('(Modal)');
      });
    });
  });

  describe('edge cases', () => {
    it('should handle rapid sequential transitions', () => {
      const state = SessionState.create('IN_PROGRESS');
      let currentStep = StepId.create(1);

      for (let i = 2; i <= 18; i++) {
        const nextStep = StepId.create(i);
        const result = StepTransitionValidator.canTransition(currentStep, nextStep, state);
        
        expect(result.isValid).toBe(true);
        currentStep = nextStep;
      }
    });

    it('should prevent transitions from terminal states', () => {
      const terminalStates = ['COMPLETED', 'FAILED', 'STOPPED_AT_STEP_18'] as const;

      terminalStates.forEach(stateValue => {
        const currentStep = StepId.create(10);
        const nextStep = StepId.create(11);
        const state = SessionState.create(stateValue);

        const result = StepTransitionValidator.canTransition(currentStep, nextStep, state);

        expect(result.isValid).toBe(false);
      });
    });

    it('should allow transition from PAUSED when resumed', () => {
      const currentStep = StepId.create(5);
      const nextStep = StepId.create(6);
      const state = SessionState.create('IN_PROGRESS');

      const result = StepTransitionValidator.canTransition(currentStep, nextStep, state);

      expect(result.isValid).toBe(true);
    });
  });
});