import { describe, it, expect } from 'vitest';
import { PageStateValidator } from 'apps/companion/main/automation/domain/services/PageStateValidator';

describe('PageStateValidator', () => {
  const validator = new PageStateValidator();

  describe('validateState', () => {
    it('should return valid when all required selectors are present', () => {
      // Arrange
      const actualState = (selector: string) => {
        return ['#add-car-button', '#cars-list'].includes(selector);
      };

      // Act
      const result = validator.validateState(actualState, {
        expectedStep: 'cars',
        requiredSelectors: ['#add-car-button', '#cars-list']
      });

      // Assert
      expect(result.isOk()).toBe(true);
      const value = result.unwrap();
      expect(value.isValid).toBe(true);
      expect(value.expectedStep).toBe('cars');
      expect(value.message).toContain('Page state valid');
    });

    it('should return invalid when required selectors are missing', () => {
      // Arrange
      const actualState = (selector: string) => {
        return selector === '#add-car-button'; // Only one of two selectors present
      };

      // Act
      const result = validator.validateState(actualState, {
        expectedStep: 'cars',
        requiredSelectors: ['#add-car-button', '#cars-list']
      });

      // Assert
      expect(result.isOk()).toBe(true);
      const value = result.unwrap();
      expect(value.isValid).toBe(false);
      expect(value.expectedStep).toBe('cars');
      expect(value.missingSelectors).toEqual(['#cars-list']);
      expect(value.message).toContain('missing required elements');
    });

    it('should return invalid when forbidden selectors are present', () => {
      // Arrange
      const actualState = (selector: string) => {
        return ['#add-car-button', '#set-track'].includes(selector);
      };

      // Act
      const result = validator.validateState(actualState, {
        expectedStep: 'cars',
        requiredSelectors: ['#add-car-button'],
        forbiddenSelectors: ['#set-track'] // Should NOT be on track page yet
      });

      // Assert
      expect(result.isOk()).toBe(true);
      const value = result.unwrap();
      expect(value.isValid).toBe(false);
      expect(value.expectedStep).toBe('cars');
      expect(value.unexpectedSelectors).toEqual(['#set-track']);
      expect(value.message).toContain('unexpected elements');
    });

    it('should handle empty forbidden selectors array', () => {
      // Arrange
      const actualState = (selector: string) => {
        return selector === '#add-car-button';
      };

      // Act
      const result = validator.validateState(actualState, {
        expectedStep: 'cars',
        requiredSelectors: ['#add-car-button'],
        forbiddenSelectors: []
      });

      // Assert
      expect(result.isOk()).toBe(true);
      const value = result.unwrap();
      expect(value.isValid).toBe(true);
    });

    it('should handle undefined forbidden selectors', () => {
      // Arrange
      const actualState = (selector: string) => {
        return selector === '#add-car-button';
      };

      // Act
      const result = validator.validateState(actualState, {
        expectedStep: 'cars',
        requiredSelectors: ['#add-car-button']
        // forbiddenSelectors is undefined
      });

      // Assert
      expect(result.isOk()).toBe(true);
      const value = result.unwrap();
      expect(value.isValid).toBe(true);
    });

    it('should return error result when actualState function throws', () => {
      // Arrange
      const actualState = () => {
        throw new Error('Selector evaluation failed');
      };

      // Act
      const result = validator.validateState(actualState, {
        expectedStep: 'cars',
        requiredSelectors: ['#add-car-button']
      });

      // Assert
      expect(result.isErr()).toBe(true);
      const error = result.unwrapErr();
      expect(error.message).toContain('Selector evaluation failed');
    });

    it('should provide clear error messages for missing selectors', () => {
      // Arrange
      const actualState = () => false; // Nothing present

      // Act
      const result = validator.validateState(actualState, {
        expectedStep: 'track',
        requiredSelectors: ['#set-track', '#track-search']
      });

      // Assert
      expect(result.isOk()).toBe(true);
      const value = result.unwrap();
      expect(value.isValid).toBe(false);
      expect(value.message).toBe('Page state mismatch: Expected to be on "track" page but missing required elements');
      expect(value.missingSelectors).toEqual(['#set-track', '#track-search']);
    });

    it('should validate complex state with both required and forbidden selectors', () => {
      // Arrange - Simulate being on Cars page but Track page elements leaked through
      const actualState = (selector: string) => {
        const presentSelectors = ['#add-car-button', '#cars-list', '#set-track'];
        return presentSelectors.includes(selector);
      };

      // Act
      const result = validator.validateState(actualState, {
        expectedStep: 'cars',
        requiredSelectors: ['#add-car-button', '#cars-list'],
        forbiddenSelectors: ['#set-track', '#track-search']
      });

      // Assert
      expect(result.isOk()).toBe(true);
      const value = result.unwrap();
      expect(value.isValid).toBe(false); // Invalid due to forbidden selector
      expect(value.unexpectedSelectors).toEqual(['#set-track']);
      expect(value.message).toContain('unexpected elements');
    });
  });
});