/**
 * ValidationAdapter Tests
 *
 * Tests for the validation adapter utility that transforms HTML Editor
 * validation data to ErrorInfoNote format.
 */

import {
  transformValidationToErrorInfo,
  hasValidationErrors,
  getValidationSummary
} from '../validationAdapter';

// Mock validation object
const createMockValidation = (issues = [], isValidating = false) => ({
  isValidating,
  getAllIssues: jest.fn(() => issues),
  isClean: jest.fn(() => issues.length === 0),
  summary: {
    totalErrors: issues.filter(i => i.severity === 'error').length,
    totalWarnings: issues.filter(i => i.severity === 'warning').length,
    hasSecurityIssues: issues.some(i => i.source === 'security')
  }
});

describe('transformValidationToErrorInfo', () => {
  it('returns empty error messages when validation is null', () => {
    const result = transformValidationToErrorInfo(null);
    expect(result).toEqual({
      errorMessages: {
        LIQUID_ERROR_MSG: [],
        STANDARD_ERROR_MSG: []
      }
    });
  });

  it('returns empty error messages when validation is validating', () => {
    const validation = createMockValidation([], true);
    const result = transformValidationToErrorInfo(validation);
    expect(result).toEqual({
      errorMessages: {
        LIQUID_ERROR_MSG: [],
        STANDARD_ERROR_MSG: []
      }
    });
  });

  it('separates liquid and standard errors correctly', () => {
    const issues = [
      {
        message: 'Liquid syntax error',
        source: 'liquid-validator',
        severity: 'error',
        line: 1,
        column: 5
      },
      {
        message: 'HTML validation error',
        source: 'htmlhint',
        severity: 'error',
        line: 2,
        column: 10,
        rule: 'tag-pair'
      },
      {
        message: 'Another liquid error',
        rule: 'liquid-malformed',
        severity: 'warning'
      }
    ];

    const validation = createMockValidation(issues);
    const result = transformValidationToErrorInfo(validation);

    expect(result.errorMessages.LIQUID_ERROR_MSG).toHaveLength(2);
    expect(result.errorMessages.STANDARD_ERROR_MSG).toHaveLength(1);

    // Check liquid error formatting
    expect(result.errorMessages.LIQUID_ERROR_MSG[0]).toContain('Liquid syntax error');
    expect(result.errorMessages.LIQUID_ERROR_MSG[0]).toContain('Line 1, Char 5');

    // Check standard error formatting
    expect(result.errorMessages.STANDARD_ERROR_MSG[0]).toContain('HTML validation error');
    expect(result.errorMessages.STANDARD_ERROR_MSG[0]).toContain('Line 2, Char 10');
    expect(result.errorMessages.STANDARD_ERROR_MSG[0]).toContain('tag-pair');
  });

  it('formats error messages with line and column info', () => {
    const issues = [
      {
        message: 'Test error',
        source: 'htmlhint',
        severity: 'error',
        line: 5,
        column: 15,
        rule: 'test-rule'
      }
    ];

    const validation = createMockValidation(issues);
    const result = transformValidationToErrorInfo(validation);

    const errorMessage = result.errorMessages.STANDARD_ERROR_MSG[0];
    expect(errorMessage).toBe('Test error Line 5, Char 15. • test-rule');
  });

  it('handles errors without line/column info', () => {
    const issues = [
      {
        message: 'General error',
        source: 'custom',
        severity: 'error'
      }
    ];

    const validation = createMockValidation(issues);
    const result = transformValidationToErrorInfo(validation);

    expect(result.errorMessages.STANDARD_ERROR_MSG[0]).toBe('General error');
  });

  it('works with both email and inapp variants', () => {
    const issues = [
      {
        message: 'Test error',
        source: 'liquid-validator',
        severity: 'error'
      }
    ];

    const validation = createMockValidation(issues);

    const emailResult = transformValidationToErrorInfo(validation, 'email');
    const inappResult = transformValidationToErrorInfo(validation, 'inapp');

    expect(emailResult.errorMessages.LIQUID_ERROR_MSG).toHaveLength(1);
    expect(inappResult.errorMessages.LIQUID_ERROR_MSG).toHaveLength(1);
  });
});

describe('hasValidationErrors', () => {
  it('returns false when validation is null', () => {
    expect(hasValidationErrors(null)).toBe(false);
  });

  it('returns false when validation is validating', () => {
    const validation = createMockValidation([], true);
    expect(hasValidationErrors(validation)).toBe(false);
  });

  it('returns false when there are no issues', () => {
    const validation = createMockValidation([]);
    expect(hasValidationErrors(validation)).toBe(false);
  });

  it('returns true when there are validation issues', () => {
    const issues = [
      {
        message: 'Test error',
        source: 'htmlhint',
        severity: 'error'
      }
    ];
    const validation = createMockValidation(issues);
    expect(hasValidationErrors(validation)).toBe(true);
  });
});

describe('getValidationSummary', () => {
  it('returns default summary when validation is null', () => {
    const result = getValidationSummary(null);
    expect(result).toEqual({
      totalErrors: 0,
      totalWarnings: 0,
      hasLiquidErrors: false
    });
  });

  it('calculates summary correctly with mixed issues', () => {
    const issues = [
      {
        message: 'Error 1',
        source: 'htmlhint',
        severity: 'error'
      },
      {
        message: 'Warning 1',
        source: 'css-validator',
        severity: 'warning'
      },
      {
        message: 'Liquid error',
        source: 'liquid-validator',
        severity: 'error'
      }
    ];

    const validation = createMockValidation(issues);
    const result = getValidationSummary(validation);

    expect(result).toEqual({
      totalErrors: 2,
      totalWarnings: 1,
      hasLiquidErrors: true,
      totalIssues: 3
    });
  });

  it('detects liquid errors by rule name', () => {
    const issues = [
      {
        message: 'Liquid rule error',
        source: 'custom',
        severity: 'error',
        rule: 'liquid-malformed'
      }
    ];

    const validation = createMockValidation(issues);
    const result = getValidationSummary(validation);

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

  it('detects liquid errors by message content', () => {
    const issues = [
      {
        message: 'Invalid liquid syntax detected',
        source: 'custom',
        severity: 'error'
      }
    ];

    const validation = createMockValidation(issues);
    const result = getValidationSummary(validation);

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

describe('validationAdapter error handling', () => {
  describe('transformValidationToErrorInfo error handling', () => {
    it('handles validation without getAllIssues method (line 33-36)', () => {
      const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
      const validation = {
        isValidating: false,
        // Missing getAllIssues method
      };

      const result = transformValidationToErrorInfo(validation);

      expect(consoleSpy).toHaveBeenCalledWith(
        expect.stringContaining('[validationAdapter] validation.getAllIssues is not a function'),
        validation
      );
      expect(result).toEqual({
        errorMessages: {
          LIQUID_ERROR_MSG: [],
          STANDARD_ERROR_MSG: [],
        },
      });

      consoleSpy.mockRestore();
    });

    it('handles getAllIssues returning non-array (line 40-43)', () => {
      const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
      const validation = {
        isValidating: false,
        getAllIssues: jest.fn(() => 'not an array'), // Returns string instead of array
      };

      const result = transformValidationToErrorInfo(validation);

      expect(consoleSpy).toHaveBeenCalledWith(
        expect.stringContaining('[validationAdapter] validation.getAllIssues() did not return an array'),
        'not an array'
      );
      expect(result).toEqual({
        errorMessages: {
          LIQUID_ERROR_MSG: [],
          STANDARD_ERROR_MSG: [],
        },
      });

      consoleSpy.mockRestore();
    });
  });

  describe('hasValidationErrors error handling', () => {
    it('handles validation without getAllIssues method (line 106-110)', () => {
      const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
      const validation = {
        isValidating: false,
        // Missing getAllIssues method
      };

      const result = hasValidationErrors(validation);

      expect(consoleSpy).toHaveBeenCalledWith(
        expect.stringContaining('[validationAdapter] validation.getAllIssues is not a function'),
        validation
      );
      expect(result).toBe(false);

      consoleSpy.mockRestore();
    });

    it('handles getAllIssues returning non-array (line 112-116)', () => {
      const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
      const validation = {
        isValidating: false,
        getAllIssues: jest.fn(() => null), // Returns null instead of array
      };

      const result = hasValidationErrors(validation);

      expect(consoleSpy).toHaveBeenCalledWith(
        expect.stringContaining('[validationAdapter] validation.getAllIssues() did not return an array'),
        null
      );
      expect(result).toBe(false);

      consoleSpy.mockRestore();
    });
  });

  describe('getValidationSummary error handling', () => {
    it('handles validation without getAllIssues method (line 131-135)', () => {
      const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
      const validation = {
        isValidating: false,
        // Missing getAllIssues method
      };

      const result = getValidationSummary(validation);

      expect(consoleSpy).toHaveBeenCalledWith(
        expect.stringContaining('[validationAdapter] validation.getAllIssues is not a function'),
        validation
      );
      expect(result).toEqual({
        totalErrors: 0,
        totalWarnings: 0,
        hasLiquidErrors: false,
      });

      consoleSpy.mockRestore();
    });

    it('handles getAllIssues returning non-array (line 138-141)', () => {
      const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
      const validation = {
        isValidating: false,
        getAllIssues: jest.fn(() => ({})), // Returns object instead of array
      };

      const result = getValidationSummary(validation);

      expect(consoleSpy).toHaveBeenCalledWith(
        expect.stringContaining('[validationAdapter] validation.getAllIssues() did not return an array'),
        {}
      );
      expect(result).toEqual({
        totalErrors: 0,
        totalWarnings: 0,
        hasLiquidErrors: false,
      });

      consoleSpy.mockRestore();
    });
  });
});

