import {
  validateTemplateName,
  validateTitle,
  validateUrl,
  validateMessageContent,
} from './validation';
import { isValidHttpUrl } from './urlValidation';

// Mock the urlValidation module
jest.mock('./urlValidation', () => ({
  isValidHttpUrl: jest.fn(),
}));

// Mock the tagValidations module
jest.mock('../../../../utils/tagValidations', () => ({
  validateTags: jest.fn(),
}));

// Mock the globalMessages
jest.mock('../../../Cap/messages', () => ({
  unsupportedTagsValidationError: {
    defaultMessage: 'Unsupported tags: {unsupportedTags}',
  },
  unbalanacedCurlyBraces: {
    defaultMessage: 'Unbalanced curly braces',
  },
}));

import { validateTags } from '../../../../utils/tagValidations';
import globalMessages from '../../../Cap/messages';

describe('validation', () => {
  let mockFormatMessage;
  const mockMessages = {
    titleRequired: {
      defaultMessage: 'Title is required',
    },
    urlRequired: {
      defaultMessage: 'URL is required',
    },
    urlInvalid: {
      defaultMessage: 'URL is invalid',
    },
    messageRequired: {
      defaultMessage: 'Message is required',
    },
    personalizationTokensErrorMessage: {
      defaultMessage: 'Personalization tags are not supported for anonymous customers',
    },
  };

  beforeEach(() => {
    jest.clearAllMocks();
    mockFormatMessage = jest.fn((message, values) => {
      if (values) {
        return message.defaultMessage.replace('{unsupportedTags}', values.unsupportedTags);
      }
      return message.defaultMessage || message;
    });
  });

  describe('validateTemplateName', () => {
    it('should return true for empty string', () => {
      expect(validateTemplateName('')).toBe(true);
    });

    it('should return true for whitespace-only string', () => {
      expect(validateTemplateName('   ')).toBe(true);
    });

    it('should return true for null', () => {
      expect(validateTemplateName(null)).toBe(true);
    });

    it('should return true for undefined', () => {
      expect(validateTemplateName(undefined)).toBe(true);
    });

    it('should return false for valid template name', () => {
      expect(validateTemplateName('Valid Template Name')).toBe(false);
    });

    it('should return false for template name with leading/trailing spaces that has content', () => {
      expect(validateTemplateName('  Valid Template  ')).toBe(false);
    });
  });

  describe('validateTitle', () => {
    it('should return error message for empty string', () => {
      const result = validateTitle('', mockFormatMessage, mockMessages);
      expect(result).toBe('Title is required');
      expect(mockFormatMessage).toHaveBeenCalledWith(mockMessages.titleRequired);
    });

    it('should return error message for whitespace-only string', () => {
      const result = validateTitle('   ', mockFormatMessage, mockMessages);
      expect(result).toBe('Title is required');
    });

    it('should return error message for null', () => {
      const result = validateTitle(null, mockFormatMessage, mockMessages);
      expect(result).toBe('Title is required');
    });

    it('should return error message for undefined', () => {
      const result = validateTitle(undefined, mockFormatMessage, mockMessages);
      expect(result).toBe('Title is required');
    });

    it('should return empty string for valid title', () => {
      const result = validateTitle('Valid Title', mockFormatMessage, mockMessages);
      expect(result).toBe('');
    });

    it('should return empty string for title with content after trimming', () => {
      const result = validateTitle('  Valid Title  ', mockFormatMessage, mockMessages);
      expect(result).toBe('');
    });

    it('should return personalization error when restrictPersonalization is true and title has personalization tags', () => {
      const result = validateTitle(
        'Hello {{name}}',
        mockFormatMessage,
        mockMessages,
        true
      );
      expect(result).toBe('Personalization tags are not supported for anonymous customers');
      expect(mockFormatMessage).toHaveBeenCalledWith(mockMessages.personalizationTokensErrorMessage);
    });

    it('should return brace error when validationConfig is provided and validateTags returns isBraceError', () => {
      const validationConfig = { tagsParam: [], location: {}, tagModule: '' };
      validateTags.mockReturnValue({ isBraceError: true });
      const result = validateTitle(
        'Valid Title',
        mockFormatMessage,
        mockMessages,
        false,
        validationConfig,
        false
      );
      expect(result).toBe('Unbalanced curly braces');
      expect(mockFormatMessage).toHaveBeenCalledWith(globalMessages.unbalanacedCurlyBraces);
      expect(validateTags).toHaveBeenCalledWith({
        content: 'Valid Title',
        ...validationConfig,
        isFullMode: false,
      });
    });

    it('should not run tag validation when validationConfig is null', () => {
      validateTags.mockClear();
      const result = validateTitle('Valid Title', mockFormatMessage, mockMessages, false, null);
      expect(result).toBe('');
      expect(validateTags).not.toHaveBeenCalled();
    });

    it('should not run tag validation when validationConfig is undefined', () => {
      validateTags.mockClear();
      const result = validateTitle('Valid Title', mockFormatMessage, mockMessages, false, undefined);
      expect(result).toBe('');
      expect(validateTags).not.toHaveBeenCalled();
    });
  });

  describe('validateUrl', () => {
    beforeEach(() => {
      isValidHttpUrl.mockClear();
    });

    it('should return error message for empty string', () => {
      const result = validateUrl('', mockFormatMessage, mockMessages);
      expect(result).toBe('URL is required');
      expect(mockFormatMessage).toHaveBeenCalledWith(mockMessages.urlRequired);
      expect(isValidHttpUrl).not.toHaveBeenCalled();
    });

    it('should return error message for whitespace-only string', () => {
      const result = validateUrl('   ', mockFormatMessage, mockMessages);
      expect(result).toBe('URL is required');
    });

    it('should return error message for null', () => {
      const result = validateUrl(null, mockFormatMessage, mockMessages);
      expect(result).toBe('URL is required');
    });

    it('should return error message for undefined', () => {
      const result = validateUrl(undefined, mockFormatMessage, mockMessages);
      expect(result).toBe('URL is required');
    });

    it('should return error message for invalid URL', () => {
      isValidHttpUrl.mockReturnValue(false);
      const result = validateUrl('not-a-url', mockFormatMessage, mockMessages);
      expect(result).toBe('URL is invalid');
      expect(mockFormatMessage).toHaveBeenCalledWith(mockMessages.urlInvalid);
      expect(isValidHttpUrl).toHaveBeenCalledWith('not-a-url');
    });

    it('should return empty string for valid URL', () => {
      isValidHttpUrl.mockReturnValue(true);
      const result = validateUrl('https://example.com', mockFormatMessage, mockMessages);
      expect(result).toBe('');
      expect(isValidHttpUrl).toHaveBeenCalledWith('https://example.com');
    });

    it('should pass URL with whitespace to isValidHttpUrl without trimming', () => {
      isValidHttpUrl.mockReturnValue(true);
      const result = validateUrl('  https://example.com  ', mockFormatMessage, mockMessages);
      expect(result).toBe('');
      // Contract: validateUrl delegates to isValidHttpUrl with original (untrimmed) value
      expect(isValidHttpUrl).toHaveBeenCalledWith('  https://example.com  ');
    });
  });

  describe('validateMessageContent', () => {
    const mockValidationConfig = {
      tagsParam: [],
      location: {},
      tagModule: '',
    };

    beforeEach(() => {
      validateTags.mockClear();
    });

    it('should return error message for empty string', () => {
      const result = validateMessageContent('', mockFormatMessage, mockMessages, mockValidationConfig);
      expect(result).toBe('Message is required');
      expect(mockFormatMessage).toHaveBeenCalledWith(mockMessages.messageRequired);
      expect(validateTags).not.toHaveBeenCalled();
    });

    it('should return error message for whitespace-only string', () => {
      const result = validateMessageContent('   ', mockFormatMessage, mockMessages, mockValidationConfig);
      expect(result).toBe('Message is required');
    });

    it('should return error message for null', () => {
      const result = validateMessageContent(null, mockFormatMessage, mockMessages, mockValidationConfig);
      expect(result).toBe('Message is required');
    });

    it('should return error message for undefined', () => {
      const result = validateMessageContent(undefined, mockFormatMessage, mockMessages, mockValidationConfig);
      expect(result).toBe('Message is required');
    });

    it('should return empty string for valid message without tags', () => {
      validateTags.mockReturnValue({});
      const result = validateMessageContent('Valid message', mockFormatMessage, mockMessages, mockValidationConfig);
      expect(result).toBe('');
      expect(validateTags).toHaveBeenCalledWith({
        content: 'Valid message',
        ...mockValidationConfig,
      });
    });

    it('should return error message for unbalanced curly braces', () => {
      validateTags.mockReturnValue({
        isBraceError: true,
      });
      const result = validateMessageContent('Message with {unclosed', mockFormatMessage, mockMessages, mockValidationConfig);
      expect(result).toBe('Unbalanced curly braces');
      expect(mockFormatMessage).toHaveBeenCalledWith(globalMessages.unbalanacedCurlyBraces);
    });

    it('should pass validation config to validateTags', () => {
      const customConfig = {
        tagsParam: [{ id: 1, name: 'Tag1' }],
        location: { query: { type: 'test' } },
        tagModule: 'custom',
      };
      validateTags.mockReturnValue({});
      validateMessageContent('Valid message', mockFormatMessage, mockMessages, customConfig);
      expect(validateTags).toHaveBeenCalledWith({
        content: 'Valid message',
        ...customConfig,
      });
    });

    it('should handle validateTags returning null', () => {
      validateTags.mockReturnValue(null);
      const result = validateMessageContent('Valid message', mockFormatMessage, mockMessages, mockValidationConfig);
      expect(result).toBe('');
    });

    it('should handle validateTags returning undefined', () => {
      validateTags.mockReturnValue(undefined);
      const result = validateMessageContent('Valid message', mockFormatMessage, mockMessages, mockValidationConfig);
      expect(result).toBe('');
    });

    it('should pass message with whitespace to validateTags without trimming', () => {
      validateTags.mockReturnValue({});
      const result = validateMessageContent('  Valid message  ', mockFormatMessage, mockMessages, mockValidationConfig);
      expect(result).toBe('');
      // Contract: validateMessageContent delegates to validateTags with original (untrimmed) value
      expect(validateTags).toHaveBeenCalledWith({
        content: '  Valid message  ',
        ...mockValidationConfig,
      });
    });

    it('should return personalization error when restrictPersonalization is true and message has personalization tags', () => {
      validateTags.mockReturnValue({});
      const result = validateMessageContent(
        'Hello {{name}}',
        mockFormatMessage,
        mockMessages,
        mockValidationConfig,
        true,
        true
      );
      expect(result).toBe('Personalization tags are not supported for anonymous customers');
      expect(mockFormatMessage).toHaveBeenCalledWith(mockMessages.personalizationTokensErrorMessage);
    });

    it('should pass isFullMode to validateTags when provided', () => {
      validateTags.mockReturnValue({});
      validateMessageContent('Valid message', mockFormatMessage, mockMessages, mockValidationConfig, true);
      expect(validateTags).toHaveBeenCalledWith({
        content: 'Valid message',
        ...mockValidationConfig,
        isFullMode: true,
      });
    });
  });
});

