/**
 * Test suite for commonUtils utility functions
 */
import {
  apiMessageFormatHandler,
  addBaseToTemplate,
  isEmbeddedEditOrPreview,
  transformCustomFieldsData,
  isTagIncluded,
  getChannelData,
  validateCarouselCards,
  hasPersonalizationTags,
  getMessageForDevice,
  getTitleForDevice,
  checkForPersonalizationTokens,
  extractContent,
} from '../commonUtils';

// Use actual constant values as they're defined in the source
const EMBEDDED = 'embedded';
const EDIT = 'edit';
const PREVIEW = 'preview';

describe('commonUtils Utility Functions', () => {
  describe('apiMessageFormatHandler', () => {
    it('should return a FormattedMessage component', () => {
      const result = apiMessageFormatHandler('test.id', 'Fallback message');
      expect(result).toBeDefined();
      expect(result.type).toBeDefined();
    });

    it('should pass id and defaultMessage props', () => {
      const result = apiMessageFormatHandler('app.test', 'Default text');
      expect(result.props.id).toBe('app.test');
      expect(result.props.defaultMessage).toBe('Default text');
    });
  });

  describe('addBaseToTemplate', () => {
    it('should add base from first history item if not present', () => {
      const template = {
        versions: {
          history: [{ subject: 'First version', content: 'Old content' }],
        },
      };
      const result = addBaseToTemplate(template);

      expect(result.versions.base).toBeDefined();
      expect(result.versions.base.subject).toBe('First version');
      expect(result.versions.base.content).toBe('Old content');
    });

    it('should preserve existing base subject if present', () => {
      const template = {
        versions: {
          base: { subject: 'Existing subject' },
          history: [{ subject: 'History subject' }],
        },
      };
      const result = addBaseToTemplate(template);

      expect(result.versions.base.subject).toBe('Existing subject');
    });

    it('should return original template if no history', () => {
      const template = { versions: {} };
      const result = addBaseToTemplate(template);

      expect(result).toEqual(template);
    });

    it('should return original template if template is null/undefined', () => {
      expect(addBaseToTemplate(null)).toBeNull();
      expect(addBaseToTemplate(undefined)).toBeUndefined();
    });

    it('should handle empty history array', () => {
      const template = { versions: { history: [] } };
      const result = addBaseToTemplate(template);

      expect(result).toEqual(template);
    });
  });

  describe('isEmbeddedEditOrPreview', () => {
    it('should return true for EMBEDDED with EDIT mode', () => {
      const result = isEmbeddedEditOrPreview(EMBEDDED, EDIT);
      expect(result).toBe(true);
    });

    it('should return true for EMBEDDED with PREVIEW mode', () => {
      const result = isEmbeddedEditOrPreview(EMBEDDED, PREVIEW);
      expect(result).toBe(true);
    });

    it('should return false for non-EMBEDDED queryType', () => {
      const result = isEmbeddedEditOrPreview('other', EDIT);
      expect(result).toBe(false);
    });

    it('should return false for EMBEDDED with non-EDIT/PREVIEW mode', () => {
      const result = isEmbeddedEditOrPreview(EMBEDDED, 'view');
      expect(result).toBe(false);
    });
  });

  describe('transformCustomFieldsData', () => {
    it('should transform custom fields with loyalty_registration scope', () => {
      const customFields = {
        field1: { name: 'firstName', scope: 'loyalty_registration' },
      };
      const result = transformCustomFieldsData(customFields);

      expect(result['Registration custom fields']).toBeDefined();
      expect(result['Registration custom fields'].subtags['custom_field.firstName']).toBeDefined();
    });

    it('should transform custom fields with org_custom_field scope', () => {
      const customFields = {
        field1: { name: 'orgField', scope: 'org_custom_field', label: 'Organization Field' },
      };
      const result = transformCustomFieldsData(customFields);

      expect(result['Organization custom fields']).toBeDefined();
      expect(result['Organization custom fields'].subtags['org_custom_field.orgField']).toBeDefined();
    });

    it('should transform custom fields with store_custom_fields scope', () => {
      const customFields = {
        field1: { name: 'storeField', scope: 'store_custom_fields' },
      };
      const result = transformCustomFieldsData(customFields);

      expect(result['Organization custom fields']).toBeDefined();
      expect(result['Organization custom fields'].subtags['store_custom_field.storeField']).toBeDefined();
    });

    it('should remove empty sections', () => {
      const customFields = {
        field1: { name: 'unknownField', scope: 'unknown_scope' },
      };
      const result = transformCustomFieldsData(customFields);

      expect(Object.keys(result).length).toBe(0);
    });

    it('should handle empty custom fields object', () => {
      const result = transformCustomFieldsData({});
      expect(result).toEqual({});
    });

    it('should handle multiple fields in same section', () => {
      const customFields = {
        field1: { name: 'field1', scope: 'loyalty_registration' },
        field2: { name: 'field2', scope: 'loyalty_registration' },
      };
      const result = transformCustomFieldsData(customFields);

      expect(Object.keys(result['Registration custom fields'].subtags).length).toBe(2);
    });
  });

  describe('isTagIncluded', () => {
    it('should return true when value contains both {{ and }}', () => {
      expect(isTagIncluded('Hello {{name}}')).toBe(true);
    });

    it('should return false when value does not contain tags', () => {
      expect(isTagIncluded('Hello world')).toBe(false);
    });

    it('should return false for empty string', () => {
      // isTagIncluded returns falsy value (undefined/null) for empty string
      expect(isTagIncluded('')).toBeFalsy();
    });

    it('should return false for null or undefined', () => {
      // isTagIncluded returns falsy value for null/undefined input
      expect(isTagIncluded(null)).toBeFalsy();
      expect(isTagIncluded(undefined)).toBeFalsy();
    });

    it('should return false if only opening tag present', () => {
      expect(isTagIncluded('Hello {{ name')).toBe(false);
    });

    it('should return false if only closing tag present', () => {
      expect(isTagIncluded('Hello name}}')).toBe(false);
    });

    it('should handle multiple tags', () => {
      expect(isTagIncluded('{{firstName}} {{lastName}}')).toBe(true);
    });
  });

  describe('getChannelData', () => {
    it('should handle EMAIL channel', () => {
      const formData = {
        base: {
          en: {
            'template-content': '<p>Email body</p>',
          },
        },
      };
      const result = getChannelData('email', formData, 'en');
      expect(result).toBeDefined();
    });

    it('should handle SMS channel', () => {
      const formData = {
        base: {
          'sms-editor': 'Hello {{name}}',
        },
        'template-name': 'SMS Template',
      };
      const result = getChannelData('sms', formData, 'en');
      expect(result).toContain('Hello');
    });

    it('should return stringified JSON for unknown channel', () => {
      const formData = { someData: 'value' };
      const result = getChannelData('unknown', formData, 'en');
      expect(result).toBe(JSON.stringify(formData));
    });

    it('should be case insensitive for channel', () => {
      const formData = {
        base: {
          en: {
            'template-content': '<p>Email</p>',
          },
        },
      };
      const result = getChannelData('EMAIL', formData, 'en');
      expect(result).toBeDefined();
    });

    it('should handle missing form data gracefully', () => {
      const result = getChannelData('sms', {}, 'en');
      expect(result).toBeDefined();
    });
  });

  describe('validateCarouselCards', () => {
    it('should return valid when all cards are correct', () => {
      const carouselData = [
        {
          bodyText: 'Card 1',
          imageSrc: 'image1.jpg',
          buttons: [{ isSaved: true }],
        },
      ];
      const result = validateCarouselCards(carouselData, 'image');

      expect(result.isValid).toBe(true);
      expect(result.reasons).toHaveLength(0);
    });

    it('should detect missing body text', () => {
      const carouselData = [
        {
          bodyText: '',
          imageSrc: 'image.jpg',
        },
      ];
      const result = validateCarouselCards(carouselData, 'image');

      expect(result.isValid).toBe(false);
      expect(result.reasons[0]).toContain('bodyText empty');
    });

    it('should detect missing image when media type is image', () => {
      const carouselData = [
        {
          bodyText: 'Card text',
          imageSrc: '',
        },
      ];
      const result = validateCarouselCards(carouselData, 'image');

      expect(result.isValid).toBe(false);
      expect(result.reasons[0]).toContain('imageSrc missing');
    });

    it('should detect missing video when media type is video', () => {
      const carouselData = [
        {
          bodyText: 'Card text',
          videoSrc: '',
        },
      ];
      const result = validateCarouselCards(carouselData, 'video');

      expect(result.isValid).toBe(false);
      expect(result.reasons[0]).toContain('videoSrc missing');
    });

    it('should detect unsaved buttons', () => {
      const carouselData = [
        {
          bodyText: 'Card text',
          imageSrc: 'image.jpg',
          buttons: [{ isSaved: false }],
        },
      ];
      const result = validateCarouselCards(carouselData, 'image');

      expect(result.isValid).toBe(false);
      expect(result.reasons[0]).toContain('some buttons not saved');
    });

    it('should handle empty carousel data', () => {
      const result = validateCarouselCards([], 'image');

      expect(result.isValid).toBe(true);
      expect(result.reasons).toHaveLength(0);
    });

    it('should be case insensitive for media type', () => {
      const carouselData = [
        {
          bodyText: 'Card text',
          imageSrc: 'image.jpg',
        },
      ];
      const result = validateCarouselCards(carouselData, 'IMAGE');

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

    it('should use custom constants for media types', () => {
      const carouselData = [
        {
          bodyText: 'Card text',
          imageSrc: 'image.jpg',
        },
      ];
      const result = validateCarouselCards(
        carouselData,
        'photo',
        { imageConstant: 'PHOTO' }
      );

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

    it('should detect body errors', () => {
      const carouselData = [
        {
          bodyError: 'Invalid format',
          bodyText: 'Card text',
          imageSrc: 'image.jpg',
        },
      ];
      const result = validateCarouselCards(carouselData, 'image');

      expect(result.isValid).toBe(false);
      expect(result.reasons[0]).toContain('bodyError');
    });
  });

  describe('hasPersonalizationTags', () => {
    it('should return true for liquid tags {{  }}', () => {
      expect(hasPersonalizationTags('Hello {{name}}')).toBe(true);
    });

    it('should return true for bracket tags [ ]', () => {
      expect(hasPersonalizationTags('Hello [user.name]')).toBe(true);
    });

    it('should return false for no tags', () => {
      expect(hasPersonalizationTags('Hello world')).toBe(false);
    });

    it('should return false for empty string', () => {
      // hasPersonalizationTags returns falsy value for empty string
      expect(hasPersonalizationTags('')).toBeFalsy();
    });

    it('should handle nested tags', () => {
      expect(hasPersonalizationTags('{{outer {{inner}}}}')).toBe(true);
    });

    it('should return false for only opening tags', () => {
      expect(hasPersonalizationTags('Hello {{ world')).toBe(false);
    });
  });

  describe('getMessageForDevice', () => {
    it('should extract message for specific device', () => {
      const templateData = {
        versions: {
          android: {
            base: {
              expandableDetails: {
                message: 'Android message',
              },
            },
          },
        },
      };
      const result = getMessageForDevice(templateData, 'android');

      expect(result).toBe('Android message');
    });

    it('should return undefined if message not found', () => {
      const templateData = {
        versions: {
          android: {
            base: {},
          },
        },
      };
      const result = getMessageForDevice(templateData, 'android');

      expect(result).toBeUndefined();
    });

    it('should handle undefined templateData', () => {
      const result = getMessageForDevice(undefined, 'android');
      expect(result).toBeUndefined();
    });
  });

  describe('getTitleForDevice', () => {
    it('should extract title for specific device', () => {
      const templateData = {
        versions: {
          ios: {
            base: {
              title: 'iOS title',
            },
          },
        },
      };
      const result = getTitleForDevice(templateData, 'ios');

      expect(result).toBe('iOS title');
    });

    it('should return empty string if title not found', () => {
      const templateData = {
        versions: {
          ios: {
            base: {},
          },
        },
      };
      const result = getTitleForDevice(templateData, 'ios');

      expect(result).toBe('');
    });

    it('should handle undefined templateData', () => {
      const result = getTitleForDevice(undefined, 'ios');
      expect(result).toBe('');
    });
  });

  describe('checkForPersonalizationTokens', () => {
    it('should detect liquid tags {{ }}', () => {
      const formData = {
        tab1: {
          field1: 'Hello {{name}}',
        },
      };
      const result = checkForPersonalizationTokens(formData);

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

    it('should detect bracket tags [ ]', () => {
      const formData = {
        tab1: {
          field1: 'Hello [user.name]',
        },
      };
      const result = checkForPersonalizationTokens(formData);

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

    it('should return false when no tokens present', () => {
      const formData = {
        tab1: {
          field1: 'Hello world',
        },
      };
      const result = checkForPersonalizationTokens(formData);

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

    it('should handle empty form data', () => {
      const result = checkForPersonalizationTokens({});
      expect(result).toBe(false);
    });

    it('should handle null form data', () => {
      const result = checkForPersonalizationTokens(null);
      expect(result).toBe(false);
    });

    it('should search through multiple tabs', () => {
      const formData = {
        tab1: { field1: 'No tokens' },
        tab2: { field2: 'Hello {{user}}' },
      };
      const result = checkForPersonalizationTokens(formData);

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

  describe('extractContent', () => {
    it('should extract content from regular platform data', () => {
      const platformData = {
        title: 'Title',
        message: 'Message',
      };
      const result = extractContent(platformData);

      expect(result).toContain('Title');
      expect(result).toContain('Message');
    });

    it('should extract content with CTAs', () => {
      const platformData = {
        title: 'Title',
        message: 'Message',
        ctas: [
          { text: 'Button 1' },
          { actionLink: 'Link 2' },
        ],
      };
      const result = extractContent(platformData);

      expect(result).toContain('Button 1');
      expect(result).toContain('Link 2');
    });

    it('should handle null platform data', () => {
      const result = extractContent(null);
      expect(result).toBe('');
    });

    it('should extract from BEE editor with string html', () => {
      const platformData = {
        title: 'Title',
        isBEEeditor: true,
        beeHtml: '<p>HTML content</p>',
      };
      const result = extractContent(platformData);

      expect(result).toContain('HTML content');
    });

    it('should extract from BEE editor with object html', () => {
      const platformData = {
        title: 'Title',
        isBEEeditor: true,
        beeHtml: { value: '<p>HTML content</p>' },
      };
      const result = extractContent(platformData);

      expect(result).toContain('HTML content');
    });

    it('should filter out empty values', () => {
      const platformData = {
        title: 'Title',
        message: '',
        ctas: [{ text: '' }],
      };
      const result = extractContent(platformData);

      expect(result).toBe('Title');
    });
  });
});
