/**
 * Tests for CommonTestAndPreview Main Component
 *
 * Comprehensive tests covering all functionality, state management, and edge cases
 * This is a large component (2600+ lines) so tests cover all major paths
 */

import React from 'react';
import PropTypes from 'prop-types';
import { render, screen, waitFor } from '@testing-library/react';
import { IntlProvider } from 'react-intl';
import CommonTestAndPreview from '../index';
import { CHANNELS, MEDIA_TYPE_CAROUSEL } from '../constants';

// Mock html-to-text
jest.mock('html-to-text', () => ({
  convert: jest.fn((html) => {
    // Simple mock that strips HTML tags
    if (typeof html !== 'string') return '';
    return html.replace(/<[^>]*>/g, '').trim();
  }),
}));

// Mock CapNotification
jest.mock('@capillarytech/cap-ui-library/CapNotification', () => ({
  error: jest.fn(),
  success: jest.fn(),
  warning: jest.fn(),
  info: jest.fn(),
}));

// Mock child components - must use React.createElement to avoid hoisting issues
jest.mock('../LeftPanelContent', () => {
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies
  const ReactLib = require('react');
  return {
    __esModule: true,
    default: function MockLeftPanelContent() {
      return ReactLib.createElement('div', { 'data-testid': 'left-panel' }, 'Left Panel');
    },
  };
});

jest.mock('../CustomValuesEditor', () => {
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies
  const ReactLib = require('react');
  return {
    __esModule: true,
    default: function MockCustomValuesEditor() {
      return ReactLib.createElement('div', { 'data-testid': 'custom-values-editor' }, 'Custom Values Editor');
    },
  };
});

let lastSendTestMessageProps = null;
jest.mock('../SendTestMessage', () => {
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies
  const ReactLib = require('react');
  return {
    __esModule: true,
    default: function MockSendTestMessage(props) {
      lastSendTestMessageProps = props;
      return ReactLib.createElement('div', { 'data-testid': 'send-test-message' }, 'Send Test Message');
    },
  };
});

jest.mock('../PreviewSection', () => {
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies
  const ReactLib = require('react');
  return {
    __esModule: true,
    default: function MockPreviewSection() {
      return ReactLib.createElement('div', { 'data-testid': 'preview-section' }, 'Preview Section');
    },
  };
});

// Mock utilities
jest.mock('../../../utils/cdnTransformation', () => ({
  getCdnUrl: jest.fn(({ url }) => `cdn_${url}`),
}));

// Mock services/api for add test customer flow
jest.mock('../../../services/api', () => ({
  getMembersLookup: jest.fn(),
  createTestCustomer: jest.fn(),
}));

// Mock messages - using actual message IDs from messages.js
const mockMessages = {
  'app.v2Components.TestAndPreviewSlidebox.testAndPreviewHeader': { defaultMessage: 'Preview and Test' },
  'app.v2Components.TestAndPreviewSlidebox.previewFor': { defaultMessage: 'Preview for' },
  'app.v2Components.TestAndPreviewSlidebox.defaultPreview': { defaultMessage: 'Default preview' },
  'app.v2Components.TestAndPreviewSlidebox.userProfileNotFound': { defaultMessage: "Please select a different user. User doesn't have a {channel} profile" },
  'app.v2Components.TestAndPreviewSlidebox.extractingTags': { defaultMessage: 'Extracting tags...' },
  'app.v2Components.TestAndPreviewSlidebox.noTagsExtracted': { defaultMessage: 'There are no personalization tags in this message, you can directly send out a test message' },
  'app.v2Components.TestAndPreviewSlidebox.invalidJSON': { defaultMessage: 'Invalid JSON input' },
  'app.v2Components.TestAndPreviewSlidebox.previewUpdateError': { defaultMessage: 'Failed to update preview' },
  'app.v2Components.TestAndPreviewSlidebox.testMessageSent': { defaultMessage: 'Test message sent successfully!' },
  'app.v2Components.TestAndPreviewSlidebox.testMessageFailed': { defaultMessage: 'Failed to send test message' },
};

// Test wrapper
const TestWrapper = ({ children }) => (
  <IntlProvider locale="en" messages={mockMessages}>
    {children}
  </IntlProvider>
);

TestWrapper.propTypes = {
  children: PropTypes.node,
};

TestWrapper.defaultProps = {
  children: null,
};


describe('CommonTestAndPreview', () => {
  const mockActions = {
    searchCustomersRequested: jest.fn(),
    extractTagsRequested: jest.fn(),
    updatePreviewRequested: jest.fn(),
    sendTestMessageRequested: jest.fn(),
    clearCustomerSearchState: jest.fn(),
    getTestCustomersRequested: jest.fn(),
    getTestGroupsRequested: jest.fn(),
    createMessageMetaRequested: jest.fn(),
    getPrefilledValuesRequested: jest.fn(),
    clearPrefilledValues: jest.fn(),
    clearPreviewErrors: jest.fn(),
    getSenderDetailsRequested: jest.fn(),
    getWeCrmAccountsRequested: jest.fn(),
    addTestCustomer: jest.fn(),
  };

  const defaultProps = {
    intl: {
      formatMessage: jest.fn((msg, values) => {
        if (values) {
          return msg.defaultMessage.replace('{channel}', values.channel);
        }
        return msg.defaultMessage || msg.id;
      }),
    },
    show: true,
    onClose: jest.fn(),
    channel: CHANNELS.EMAIL,
    formData: {
      'template-subject': 'Test Subject',
      0: {
        activeTab: 'base',
        base: {
          'template-content': '<html>Test Content</html>',
        },
      },
    },
    content: '',
    config: {
      enableCustomerSearch: true,
      enableTagExtraction: true,
      enableTestMessage: true,
      enableDeviceToggle: true,
    },
    actions: mockActions,
    extractedTags: [],
    isExtractingTags: false,
    customers: [],
    isSearchingCustomer: false,
    previewData: null,
    isUpdatingPreview: false,
    updatePreviewError: null,
    updatePreviewErrors: [],
    testCustomers: [],
    isFetchingTestCustomers: false,
    testGroups: [],
    isFetchingTestGroups: false,
    messageMetaConfigId: null,
    prefilledValues: {},
    fetchPrefilledValuesError: null,
    fetchPrefilledValuesErrors: [],
    isSendingTestMessage: false,
    currentTab: 1,
    senderDetailsByChannel: {},
    wecrmAccounts: [],
    isLoadingSenderDetails: false,
    orgUnitId: -1,
  };

  beforeEach(() => {
    jest.clearAllMocks();
    lastSendTestMessageProps = null;
    // Reset all mock function implementations
    Object.values(mockActions).forEach((mockFn) => {
      if (jest.isMockFunction(mockFn)) {
        mockFn.mockClear();
      }
    });
  });

  describe('Delivery settings / sender ID', () => {
    it('should call getSenderDetailsRequested when show and channel is SMS', async () => {
      render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.SMS} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(mockActions.getSenderDetailsRequested).toHaveBeenCalledWith({
          channel: CHANNELS.SMS,
          orgUnitId: -1,
        });
      });
    });

    it('should call getSenderDetailsRequested when show and channel is EMAIL', async () => {
      render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(mockActions.getSenderDetailsRequested).toHaveBeenCalledWith({
          channel: CHANNELS.EMAIL,
          orgUnitId: -1,
        });
      });
    });

    it('should call getSenderDetailsRequested and getWeCrmAccountsRequested when show and channel is WHATSAPP', async () => {
      render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.WHATSAPP} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(mockActions.getSenderDetailsRequested).toHaveBeenCalledWith({
          channel: CHANNELS.WHATSAPP,
          orgUnitId: -1,
        });
        expect(mockActions.getWeCrmAccountsRequested).toHaveBeenCalledWith({
          sourceName: CHANNELS.WHATSAPP,
        });
      });
    });

    it('should not call getSenderDetailsRequested when channel is INAPP', async () => {
      render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.INAPP} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      expect(mockActions.getSenderDetailsRequested).not.toHaveBeenCalled();
      expect(mockActions.getWeCrmAccountsRequested).not.toHaveBeenCalled();
    });

    it('should pass orgUnitId to getSenderDetailsRequested when provided', async () => {
      render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.SMS} orgUnitId={100} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(mockActions.getSenderDetailsRequested).toHaveBeenCalledWith({
          channel: CHANNELS.SMS,
          orgUnitId: 100,
        });
      });
    });

    it('should not call getSenderDetailsRequested when show is false', async () => {
      render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} show={false} channel={CHANNELS.SMS} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(screen.queryByTestId('left-panel')).toBeNull();
      });
      expect(mockActions.getSenderDetailsRequested).not.toHaveBeenCalled();
    });

    it('should pass delivery-related props to SendTestMessage for SMS channel', async () => {
      const senderDetailsByChannel = {
        [CHANNELS.SMS]: [{ domainId: 1, domainName: 'SMS Dom', gsmSenders: [], cdmaSenders: [] }],
      };
      render(
        <TestWrapper>
          <CommonTestAndPreview
            {...defaultProps}
            channel={CHANNELS.SMS}
            senderDetailsByChannel={senderDetailsByChannel}
            wecrmAccounts={[]}
          />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(screen.getByTestId('send-test-message')).toBeTruthy();
      });
      expect(lastSendTestMessageProps).toBeDefined();
      expect(lastSendTestMessageProps.deliverySettings).toBeDefined();
      expect(lastSendTestMessageProps.senderDetailsOptions).toEqual(senderDetailsByChannel[CHANNELS.SMS]);
      expect(lastSendTestMessageProps.wecrmAccounts).toEqual([]);
      expect(typeof lastSendTestMessageProps.onSaveDeliverySettings).toBe('function');
      expect(lastSendTestMessageProps.isLoadingSenderDetails).toBe(false);
    });

    it('should pass formDataForSendTest (formData when provided) to SendTestMessage', async () => {
      render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(lastSendTestMessageProps).toBeDefined();
      });
      expect(lastSendTestMessageProps.formData).toEqual(defaultProps.formData);
    });

    it('should auto-set SMS delivery settings from TRAI registered sender IDs when DLT is enabled', async () => {
      const senderDetailsByChannel = {
        [CHANNELS.SMS]: [
          {
            domainId: 1,
            dgmId: 11,
            gsmSenders: [{ value: 'SENDER_A' }],
            cdmaSenders: [{ value: 'CDMA_A' }],
          },
          {
            domainId: 2,
            dgmId: 22,
            gsmSenders: [{ value: 'SENDER_B' }, { value: 'SENDER_C' }],
            cdmaSenders: [{ value: 'CDMA_B' }],
          },
        ],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview
            {...defaultProps}
            channel={CHANNELS.SMS}
            formData={{
              templateConfigs: {
                traiDltEnabled: true,
                registeredSenderIds: ['SENDER_B'],
              },
            }}
            senderDetailsByChannel={senderDetailsByChannel}
          />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(lastSendTestMessageProps.deliverySettings).toEqual({
          domainId: 2,
          domainGatewayMapId: 22,
          gsmSenderId: 'SENDER_B',
          cdmaSenderId: 'CDMA_B',
        });
      });
    });

    it('should preserve existing SMS auto-set logic when TRAI DLT is not enabled', async () => {
      const senderDetailsByChannel = {
        [CHANNELS.SMS]: [
          {
            domainId: 1,
            dgmId: 11,
            gsmSenders: [{ value: 'SENDER_A' }, { value: 'SENDER_A_DEFAULT', default: true }],
            cdmaSenders: [{ value: 'CDMA_A', default: true }],
          },
          {
            domainId: 2,
            dgmId: 22,
            gsmSenders: [{ value: 'SENDER_B' }],
            cdmaSenders: [{ value: 'CDMA_B' }],
          },
        ],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview
            {...defaultProps}
            channel={CHANNELS.SMS}
            formData={{
              templateConfigs: {
                traiDltEnabled: false,
                registeredSenderIds: ['SENDER_B'],
              },
            }}
            senderDetailsByChannel={senderDetailsByChannel}
          />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(lastSendTestMessageProps.deliverySettings).toEqual({
          domainId: 1,
          domainGatewayMapId: 11,
          gsmSenderId: 'SENDER_A_DEFAULT',
          cdmaSenderId: 'CDMA_A',
        });
      });
    });

    it('should keep SMS delivery settings empty when DLT is enabled and no registered sender ID matches', async () => {
      const senderDetailsByChannel = {
        [CHANNELS.SMS]: [
          {
            domainId: 1,
            dgmId: 11,
            gsmSenders: [{ value: 'SENDER_A' }],
            cdmaSenders: [{ value: 'CDMA_A' }],
          },
        ],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview
            {...defaultProps}
            channel={CHANNELS.SMS}
            formData={{
              templateConfigs: {
                traiDltEnabled: true,
                registeredSenderIds: ['SENDER_X'],
              },
            }}
            senderDetailsByChannel={senderDetailsByChannel}
          />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(lastSendTestMessageProps).toBeDefined();
      });

      expect(lastSendTestMessageProps.deliverySettings).toEqual({
        domainId: null,
        domainGatewayMapId: null,
        gsmSenderId: '',
        cdmaSenderId: '',
      });
    });

    it('should auto-set WhatsApp delivery settings from formData accountName when matching account exists', async () => {
      const senderDetailsByChannel = {
        [CHANNELS.WHATSAPP]: [
          {
            domainId: 1,
            sourceAccountIdentifier: 'waba-1',
            gsmSenders: [{ value: '+1111111111' }],
          },
          {
            domainId: 2,
            sourceAccountIdentifier: 'waba-2',
            gsmSenders: [{ value: '+2222222222' }],
          },
        ],
      };
      const wecrmAccounts = [
        { name: 'Account One', sourceAccountIdentifier: 'waba-1' },
        { name: 'Account Two', sourceAccountIdentifier: 'waba-2' },
      ];

      render(
        <TestWrapper>
          <CommonTestAndPreview
            {...defaultProps}
            channel={CHANNELS.WHATSAPP}
            formData={{ accountName: 'Account Two', templateMsg: 'WhatsApp test' }}
            senderDetailsByChannel={senderDetailsByChannel}
            wecrmAccounts={wecrmAccounts}
          />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(lastSendTestMessageProps).toBeDefined();
        expect(lastSendTestMessageProps.deliverySettings).toEqual({
          domainId: 2,
          senderMobNum: '+2222222222',
          sourceAccountIdentifier: 'waba-2',
        });
      });
    });

    it('should include delivery settings in payload when handleSendTestMessage is called for EMAIL', async () => {
      render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(lastSendTestMessageProps).toBeDefined();
        expect(typeof lastSendTestMessageProps.handleSendTestMessage).toBe('function');
      });
      lastSendTestMessageProps.handleSendTestMessage();
      expect(mockActions.createMessageMetaRequested).toHaveBeenCalled();
      const [initialPayload] = mockActions.createMessageMetaRequested.mock.calls[0];
      expect(initialPayload.emailDeliverySettings).toBeDefined();
      expect(initialPayload.emailDeliverySettings.channelSettings).toBeDefined();
      expect(initialPayload.emailDeliverySettings.channelSettings.channel).toBe(CHANNELS.EMAIL);
    });

    it('should include delivery settings in payload when handleSendTestMessage is called for SMS', async () => {
      render(
        <TestWrapper>
          <CommonTestAndPreview
            {...defaultProps}
            channel={CHANNELS.SMS}
            formData={{ 'sms-editor': 'Test SMS' }}
          />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(lastSendTestMessageProps).toBeDefined();
      });
      lastSendTestMessageProps.handleSendTestMessage();
      expect(mockActions.createMessageMetaRequested).toHaveBeenCalled();
      const [initialPayload] = mockActions.createMessageMetaRequested.mock.calls[0];
      expect(initialPayload.smsDeliverySettings).toBeDefined();
      expect(initialPayload.smsDeliverySettings.channelSettings).toBeDefined();
      expect(initialPayload.smsDeliverySettings.channelSettings.channel).toBe(CHANNELS.SMS);
    });
  });

  describe('Carousel payload (getCarouselMappedData) - handleSendTestMessage', () => {
    it('should map empty carouselData to empty cards when mediaType is CAROUSEL', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.WHATSAPP,
        formData: {
          templateMsg: 'Message',
          mediaType: MEDIA_TYPE_CAROUSEL,
          carouselData: [],
        },
      };
      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(lastSendTestMessageProps).toBeDefined();
        expect(typeof lastSendTestMessageProps.handleSendTestMessage).toBe('function');
      });
      lastSendTestMessageProps.handleSendTestMessage();
      expect(mockActions.createMessageMetaRequested).toHaveBeenCalled();
      const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
      expect(payload.whatsappMessageContent.templateConfigs.cards).toEqual([]);
      expect(payload.whatsappMessageContent.templateConfigs.mediaType).toBe('IMAGE');
    });

    it('should map carousel with IMAGE media and bodyText to cards with media.url', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.WHATSAPP,
        formData: {
          templateMsg: 'Message',
          mediaType: MEDIA_TYPE_CAROUSEL,
          carouselMediaType: 'IMAGE',
          carouselData: [
            {
              bodyText: 'Card body',
              imageUrl: 'https://image.example.com/1.jpg',
              mediaType: 'image',
              buttons: [],
            },
          ],
        },
      };
      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(lastSendTestMessageProps).toBeDefined();
      });
      lastSendTestMessageProps.handleSendTestMessage();
      const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
      const cards = payload.whatsappMessageContent.templateConfigs.cards;
      expect(cards).toHaveLength(1);
      expect(cards[0].body).toBe('Card body');
      expect(cards[0].media).toEqual({ url: 'https://image.example.com/1.jpg' });
      expect(cards[0].mediaType).toBe('IMAGE');
      expect(cards[0].buttons).toEqual([]);
      expect(payload.whatsappMessageContent.templateConfigs.mediaType).toBe('IMAGE');
    });

    it('should map carousel with VIDEO media to cards with url and previewUrl', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.WHATSAPP,
        formData: {
          templateMsg: 'Message',
          mediaType: MEDIA_TYPE_CAROUSEL,
          carouselMediaType: 'VIDEO',
          carouselData: [
            {
              bodyText: 'Video card',
              videoUrl: 'https://video.example.com/1.mp4',
              videoPreviewImg: 'https://preview.example.com/1.jpg',
              mediaType: 'video',
              buttons: [],
            },
          ],
        },
      };
      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(lastSendTestMessageProps).toBeDefined();
      });
      lastSendTestMessageProps.handleSendTestMessage();
      const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
      const cards = payload.whatsappMessageContent.templateConfigs.cards;
      expect(cards).toHaveLength(1);
      expect(cards[0].body).toBe('Video card');
      expect(cards[0].media).toEqual({
        url: 'https://video.example.com/1.mp4',
        previewUrl: 'https://preview.example.com/1.jpg',
      });
      expect(cards[0].mediaType).toBe('VIDEO');
      expect(payload.whatsappMessageContent.templateConfigs.mediaType).toBe('VIDEO');
    });

    it('should map button type PHONE_NUMBER to buttonObj with phoneNumber', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.WHATSAPP,
        formData: {
          templateMsg: 'Message',
          mediaType: MEDIA_TYPE_CAROUSEL,
          carouselData: [
            {
              bodyText: 'Card',
              mediaType: 'image',
              imageUrl: 'https://img.url',
              buttons: [
                { type: 'PHONE_NUMBER', text: 'Call', phone_number: '+1234567890' },
              ],
            },
          ],
        },
      };
      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(lastSendTestMessageProps).toBeDefined();
      });
      lastSendTestMessageProps.handleSendTestMessage();
      const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
      const buttons = payload.whatsappMessageContent.templateConfigs.cards[0].buttons;
      expect(buttons).toHaveLength(1);
      expect(buttons[0].type).toBe('PHONE_NUMBER');
      expect(buttons[0].text).toBe('Call');
      expect(buttons[0].index).toBe(0);
      expect(buttons[0].phoneNumber).toBe('+1234567890');
    });

    it('should map button type URL without DYNAMIC_URL to buttonObj with url only', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.WHATSAPP,
        formData: {
          templateMsg: 'Message',
          mediaType: MEDIA_TYPE_CAROUSEL,
          carouselData: [
            {
              bodyText: 'Card',
              mediaType: 'image',
              imageUrl: 'https://img.url',
              buttons: [
                { type: 'URL', text: 'Open', urlType: 'STATIC', url: 'https://example.com' },
              ],
            },
          ],
        },
      };
      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(lastSendTestMessageProps).toBeDefined();
      });
      lastSendTestMessageProps.handleSendTestMessage();
      const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
      const buttons = payload.whatsappMessageContent.templateConfigs.cards[0].buttons;
      expect(buttons[0].type).toBe('URL');
      expect(buttons[0].url).toBe('https://example.com');
      expect(buttons[0].dynamicUrlPayload).toBeUndefined();
    });

    it('should set dynamicUrlPayload when button type URL and urlType DYNAMIC_URL with single template', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.WHATSAPP,
        formData: {
          templateMsg: 'Message',
          mediaType: MEDIA_TYPE_CAROUSEL,
          carouselData: [
            {
              bodyText: 'Card',
              mediaType: 'image',
              imageUrl: 'https://img.url',
              buttons: [
                { type: 'URL', text: 'Open', urlType: 'DYNAMIC_URL', url: 'https://example.com/{{id}}' },
              ],
            },
          ],
        },
      };
      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(lastSendTestMessageProps).toBeDefined();
      });
      lastSendTestMessageProps.handleSendTestMessage();
      const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
      const buttons = payload.whatsappMessageContent.templateConfigs.cards[0].buttons;
      expect(buttons[0].url).toBe('https://example.com/{{id}}');
      expect(buttons[0].dynamicUrlPayload).toBe('{{id}}');
    });

    it('should set dynamicUrlPayload to empty when urlType DYNAMIC_URL but multiple or zero matches', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.WHATSAPP,
        formData: {
          templateMsg: 'Message',
          mediaType: MEDIA_TYPE_CAROUSEL,
          carouselData: [
            {
              bodyText: 'Card',
              mediaType: 'image',
              imageUrl: 'https://img.url',
              buttons: [
                { type: 'URL', text: 'Open', urlType: 'DYNAMIC_URL', url: 'https://example.com/{{a}}{{b}}' },
              ],
            },
          ],
        },
      };
      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(lastSendTestMessageProps).toBeDefined();
      });
      lastSendTestMessageProps.handleSendTestMessage();
      const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
      const buttons = payload.whatsappMessageContent.templateConfigs.cards[0].buttons;
      expect(buttons[0].dynamicUrlPayload).toBe('');
    });

    it('should set dynamicUrlPayload to empty when urlType DYNAMIC_URL and url is null/undefined', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.WHATSAPP,
        formData: {
          templateMsg: 'Message',
          mediaType: MEDIA_TYPE_CAROUSEL,
          carouselData: [
            {
              bodyText: 'Card',
              mediaType: 'image',
              imageUrl: 'https://img.url',
              buttons: [
                { type: 'URL', text: 'Open', urlType: 'DYNAMIC_URL', url: null },
              ],
            },
          ],
        },
      };
      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(lastSendTestMessageProps).toBeDefined();
      });
      lastSendTestMessageProps.handleSendTestMessage();
      const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
      const buttons = payload.whatsappMessageContent.templateConfigs.cards[0].buttons;
      expect(buttons[0].dynamicUrlPayload).toBe('');
    });

    it('should pass through cardVarMapped and bodyTemplate on each card', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.WHATSAPP,
        formData: {
          templateMsg: 'Message',
          mediaType: MEDIA_TYPE_CAROUSEL,
          carouselData: [
            {
              bodyText: 'Body',
              cardVarMapped: { foo: 'bar' },
              bodyTemplate: 'Body {{foo}}',
              mediaType: 'image',
              imageUrl: 'https://img.url',
              buttons: [],
            },
          ],
        },
      };
      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(lastSendTestMessageProps).toBeDefined();
      });
      lastSendTestMessageProps.handleSendTestMessage();
      const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
      const card = payload.whatsappMessageContent.templateConfigs.cards[0];
      expect(card.cardVarMapped).toEqual({ foo: 'bar' });
      expect(card.bodyTemplate).toBe('Body {{foo}}');
    });

    it('should not add media url when mediaType is neither image nor video', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.WHATSAPP,
        formData: {
          templateMsg: 'Message',
          mediaType: MEDIA_TYPE_CAROUSEL,
          carouselData: [
            {
              bodyText: 'Card',
              mediaType: 'DOCUMENT',
              imageUrl: 'https://img.url',
              videoUrl: 'https://video.url',
              buttons: [],
            },
          ],
        },
      };
      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(lastSendTestMessageProps).toBeDefined();
      });
      lastSendTestMessageProps.handleSendTestMessage();
      const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
      const card = payload.whatsappMessageContent.templateConfigs.cards[0];
      expect(card.media).toEqual({});
      expect(card.mediaType).toBe('DOCUMENT');
    });

    it('should handle multiple carousel cards with mixed button types', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.WHATSAPP,
        formData: {
          templateMsg: 'Message',
          mediaType: MEDIA_TYPE_CAROUSEL,
          carouselData: [
            {
              bodyText: 'First',
              mediaType: 'image',
              imageUrl: 'https://first.jpg',
              buttons: [{ type: 'PHONE_NUMBER', text: 'Call', phone_number: '+111' }],
            },
            {
              bodyText: 'Second',
              mediaType: 'video',
              videoUrl: 'https://second.mp4',
              videoPreviewImg: 'https://second-prev.jpg',
              buttons: [{ type: 'URL', text: 'Link', urlType: 'DYNAMIC_URL', url: 'https://x/{{only}}' }],
            },
          ],
        },
      };
      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(lastSendTestMessageProps).toBeDefined();
      });
      lastSendTestMessageProps.handleSendTestMessage();
      const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
      const cards = payload.whatsappMessageContent.templateConfigs.cards;
      expect(cards).toHaveLength(2);
      expect(cards[0].body).toBe('First');
      expect(cards[0].media.url).toBe('https://first.jpg');
      expect(cards[0].buttons[0].phoneNumber).toBe('+111');
      expect(cards[1].body).toBe('Second');
      expect(cards[1].media.url).toBe('https://second.mp4');
      expect(cards[1].media.previewUrl).toBe('https://second-prev.jpg');
      expect(cards[1].buttons[0].dynamicUrlPayload).toBe('{{only}}');
    });

    it('should use carouselMediaType for templateConfigs.mediaType when provided', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.WHATSAPP,
        formData: {
          templateMsg: 'Message',
          mediaType: MEDIA_TYPE_CAROUSEL,
          carouselMediaType: 'VIDEO',
          carouselData: [
            { bodyText: 'Card', mediaType: 'image', imageUrl: 'https://img.url', buttons: [] },
          ],
        },
      };
      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(lastSendTestMessageProps).toBeDefined();
      });
      lastSendTestMessageProps.handleSendTestMessage();
      const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
      expect(payload.whatsappMessageContent.templateConfigs.mediaType).toBe('VIDEO');
    });

    it('should default templateConfigs.mediaType to IMAGE when carouselMediaType is missing', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.WHATSAPP,
        formData: {
          templateMsg: 'Message',
          mediaType: MEDIA_TYPE_CAROUSEL,
          carouselData: [
            { bodyText: 'Card', mediaType: 'image', imageUrl: 'https://img.url', buttons: [] },
          ],
        },
      };
      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );
      await waitFor(() => {
        expect(lastSendTestMessageProps).toBeDefined();
      });
      lastSendTestMessageProps.handleSendTestMessage();
      const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
      expect(payload.whatsappMessageContent.templateConfigs.mediaType).toBe('IMAGE');
    });
  });

  describe('Component Rendering', () => {
    it('should render when show is true', async () => {
      render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should not render when show is false', async () => {
      const props = {
        ...defaultProps,
        show: false,
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.queryByTestId('left-panel')).toBeNull();
      });
    });

    it('should render CapSlideBox', async () => {
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} />
        </TestWrapper>
      );

      await waitFor(() => {
        // CapSlideBox should be rendered
        expect(container.querySelector('.ant-drawer') || container.querySelector('[class*="slide"]')).toBeTruthy();
      });
    });
  });

  describe('Channel Handling', () => {
    it('should handle EMAIL channel', async () => {
      render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle SMS channel', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.SMS,
        formData: {
          0: {
            'sms-editor': 'SMS message',
          },
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle WHATSAPP channel', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.WHATSAPP,
        formData: {
          templateMsg: 'WhatsApp message',
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle RCS channel', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.RCS,
        formData: {
          rcsTitle: 'RCS Title',
          rcsDesc: 'RCS Description',
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle INAPP channel', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.INAPP,
        formData: {
          templateTitle: 'InApp Title',
          templateMsg: 'InApp Message',
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle MOBILEPUSH channel', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.MOBILEPUSH,
        formData: {
          header: 'Push Header',
          bodyText: 'Push Body',
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle VIBER channel', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.VIBER,
        formData: {
          messageContent: 'Viber message',
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle ZALO channel', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.ZALO,
        formData: {
          templateListParams: [],
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // ZALO channel doesn't render LeftPanelContent
      await waitFor(() => {
        expect(screen.queryByTestId('left-panel')).toBeNull();
        expect(screen.getByTestId('preview-section')).toBeTruthy();
      });
    });

    it('should handle WEBPUSH channel', async () => {
      const webpushContent = {
        content: { title: 'Web Push', message: 'Hello from web push' },
        accountId: 'acc-001',
      };
      const props = {
        ...defaultProps,
        channel: CHANNELS.WEBPUSH,
        content: webpushContent,
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
        expect(screen.getByTestId('preview-section')).toBeTruthy();
      });
    });

    it('should treat WEBPUSH content as object (same branch as WHATSAPP)', async () => {
      // The WEBPUSH channel uses the same contentObj branch as WHATSAPP (JSON string or object)
      const props = {
        ...defaultProps,
        channel: CHANNELS.WEBPUSH,
        content: JSON.stringify({
          content: { title: 'Stringified', message: 'Content' },
        }),
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('preview-section')).toBeTruthy();
      });
    });
  });

  describe('Device Initialization', () => {
    it('should initialize with ANDROID for SMS channel', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.SMS,
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // Device should be initialized to ANDROID for SMS
      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should initialize with DESKTOP for EMAIL channel', async () => {
      render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} />
        </TestWrapper>
      );

      // Device should be initialized to DESKTOP for EMAIL
      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should initialize with ANDROID for WHATSAPP channel', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.WHATSAPP,
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });
  });

  describe('Tag Extraction', () => {
    it('should call extractTagsRequested when handleExtractTags is called', async () => {
      const props = {
        ...defaultProps,
        extractedTags: [
          { name: 'firstName', metaData: { userDriven: false } },
        ],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // Trigger tag extraction (this would be done through UI interaction)
      // The component should call extractTagsRequested when tags are extracted
      expect(mockActions.extractTagsRequested).toBeDefined();
    });

    it('should process extracted tags and set required/optional tags', async () => {
      const props = {
        ...defaultProps,
        extractedTags: [
          {
            name: 'user',
            metaData: { userDriven: false },
            children: [
              { name: 'firstName', metaData: { userDriven: false } },
              { name: 'lastName', metaData: { userDriven: true } },
            ],
          },
        ],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // Tags should be processed and required/optional tags set
      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should skip unsubscribe tag', async () => {
      const props = {
        ...defaultProps,
        extractedTags: [
          { name: 'unsubscribe', metaData: { userDriven: false } },
          { name: 'firstName', metaData: { userDriven: false } },
        ],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // Unsubscribe tag should be skipped
      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle empty extractedTags array', async () => {
      const props = {
        ...defaultProps,
        extractedTags: [],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle null extractedTags', async () => {
      const props = {
        ...defaultProps,
        extractedTags: null,
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });
  });

  describe('Customer Selection', () => {
    it('should call getPrefilledValuesRequested when customer is selected', async () => {
      const props = {
        ...defaultProps,
        extractedTags: [
          { name: 'firstName', metaData: { userDriven: false } },
        ],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // Wait for component to render
      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });

      // Wait for component to render
      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });

      // This would normally be triggered by user interaction
      // For testing, we verify the action exists
      expect(mockActions.getPrefilledValuesRequested).toBeDefined();
    });

    it('should update custom values with prefilled values', async () => {
      const props = {
        ...defaultProps,
        extractedTags: [
          { name: 'firstName', metaData: { userDriven: false }, fullPath: 'user.firstName' },
        ],
        prefilledValues: {
          'user.firstName': 'John',
        },
        customers: [
          { id: '1', name: 'John Doe', customerId: '1' },
        ],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // Custom values should be updated with prefilled values
      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should call updatePreviewRequested when prefilled values are set', async () => {
      const props = {
        ...defaultProps,
        extractedTags: [
          { name: 'firstName', metaData: { userDriven: false }, fullPath: 'user.firstName' },
        ],
        prefilledValues: {
          'user.firstName': 'John',
        },
        customers: [
          { id: '1', name: 'John Doe', customerId: '1' },
        ],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // updatePreviewRequested should be called
      expect(mockActions.updatePreviewRequested).toBeDefined();
    });
  });

  describe('Error Handling - Error Code 7078', () => {
    it('should show error message for error code 7078 in updatePreviewErrors', async () => {
      const props = {
        ...defaultProps,
        updatePreviewErrors: [
          { code: 7078, message: 'User profile not found' },
        ],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // Error message should be generated
      expect(mockActions.clearPreviewErrors).toBeDefined();
    });

    it('should show error message for error code 7078 in fetchPrefilledValuesErrors', async () => {
      const props = {
        ...defaultProps,
        fetchPrefilledValuesErrors: [
          { code: 7078, message: 'User profile not found' },
        ],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // Error message should be generated
      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should clear errors when channel changes', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.EMAIL,
        updatePreviewErrors: [{ code: 7078 }],
      };

      const { rerender } = render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // Change channel
      rerender(
        <TestWrapper>
          <CommonTestAndPreview {...props} channel={CHANNELS.SMS} />
        </TestWrapper>
      );

      // clearPreviewErrors should be called
      expect(mockActions.clearPreviewErrors).toHaveBeenCalled();
    });

    it('should clear errors when customer is cleared', async () => {
      const props = {
        ...defaultProps,
        customers: [
          { id: '1', name: 'John Doe' },
        ],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // Customer clearing would trigger clearPreviewErrors
      expect(mockActions.clearPreviewErrors).toBeDefined();
    });
  });

  describe('Preview Updates', () => {
    it('should call updatePreviewRequested when handleUpdatePreview is called', async () => {
      render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} />
        </TestWrapper>
      );

      // handleUpdatePreview would be called through UI interaction
      expect(mockActions.updatePreviewRequested).toBeDefined();
    });

    it('should prepare correct payload for EMAIL channel', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.EMAIL,
        formData: {
          'template-subject': 'Test Subject',
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // Payload should be prepared correctly
      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should prepare correct payload for SMS channel', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.SMS,
        formData: {
          0: {
            'sms-editor': 'SMS message',
          },
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });
  });

  describe('Test Message Sending', () => {
    it('should call sendTestMessageRequested when handleSendTestMessage is called', async () => {
      const props = {
        ...defaultProps,
        selectedTestEntities: ['customer-1'],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // handleSendTestMessage would be called through UI
      expect(mockActions.sendTestMessageRequested).toBeDefined();
    });

    it('should prepare correct test message payload for EMAIL', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.EMAIL,
        formData: {
          'template-subject': 'Test Subject',
        },
        previewData: {
          resolvedBody: '<html>Resolved</html>',
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      expect(screen.getByTestId('send-test-message')).toBeTruthy();
    });

    it('should show error notification when sendTestMessageRequested callback receives false', async () => {
      const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
      mockActions.createMessageMetaRequested.mockImplementation((payload, metaId, cb) => {
        if (cb) cb({ entity: 'meta-123' });
      });
      mockActions.sendTestMessageRequested.mockImplementation((payload, cb) => {
        if (cb) cb(false);
      });
      const props = {
        ...defaultProps,
        selectedTestEntities: ['user-1'],
        testGroups: [],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      expect(lastSendTestMessageProps).toBeTruthy();
      expect(lastSendTestMessageProps.handleSendTestMessage).toBeDefined();
      lastSendTestMessageProps.handleSendTestMessage();

      await waitFor(() => {
        expect(CapNotification.error).toHaveBeenCalled();
      });
    });
  });

  describe('Content Extraction', () => {
    it('should extract EMAIL content from formData', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.EMAIL,
        formData: {
          0: {
            activeTab: 'base',
            base: {
              'template-content': '<html>Email Content</html>',
            },
          },
          'template-subject': 'Email Subject',
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should extract SMS content from formData', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.SMS,
        formData: {
          0: {
            'sms-editor': 'SMS message text',
          },
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle BEE editor content for EMAIL', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.EMAIL,
        formData: {
          0: {
            activeTab: 'base',
            base: {
              is_drag_drop: true,
            },
          },
        },
        beeInstance: {
          save: jest.fn(() => ({ html: '<html>BEE Content</html>' })),
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });
  });

  describe('Tag Resolution', () => {
    it('should resolve tags in text correctly', async () => {
      const props = {
        ...defaultProps,
        customValues: {
          'user.firstName': 'John',
          'user.lastName': 'Doe',
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // Tag resolution should work
      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle tags with nested paths', async () => {
      const props = {
        ...defaultProps,
        customValues: {
          'user.profile.firstName': 'John',
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });
  });

  describe('Device Toggle', () => {
    it('should update device when handleDeviceChange is called', async () => {
      render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} />
        </TestWrapper>
      );

      // Device change would update previewDevice state
      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });
  });

  describe('Close Handler', () => {
    it('should reset all state when handleClose is called', async () => {
      const props = {
        ...defaultProps,
        selectedCustomer: { id: '1', name: 'John' },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // handleClose would reset state
      expect(mockActions.clearPrefilledValues).toBeDefined();
    });

    it('should call onClose when handleClose is called', async () => {
      const onClose = jest.fn();
      const props = {
        ...defaultProps,
        onClose,
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // onClose would be called when slidebox closes
      expect(onClose).toBeDefined();
    });
  });

  describe('Edge Cases', () => {
    it('should handle null formData', async () => {
      const props = {
        ...defaultProps,
        formData: null,
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle empty formData', async () => {
      const props = {
        ...defaultProps,
        formData: {},
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle null content', async () => {
      const props = {
        ...defaultProps,
        content: null,
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle undefined config', async () => {
      const props = {
        ...defaultProps,
        config: undefined,
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle missing previewData', async () => {
      const props = {
        ...defaultProps,
        previewData: null,
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle all channel types', async () => {
      const channels = Object.values(CHANNELS);

      // Run sequentially to avoid multiple elements in DOM
      await channels.reduce(async (previousPromise, channel) => {
        await previousPromise;
        const { unmount, container } = render(
          <TestWrapper>
            <CommonTestAndPreview
              {...defaultProps}
              channel={channel}
            />
          </TestWrapper>
        );
        // ZALO doesn't render left-panel, all others do
        if (channel === CHANNELS.ZALO) {
          await waitFor(() => {
            expect(container.querySelector('[data-testid="left-panel"]')).toBeNull();
            expect(container.querySelector('[data-testid="preview-section"]')).toBeTruthy();
          });
        } else {
          await waitFor(() => {
            expect(container.querySelector('[data-testid="left-panel"]')).toBeTruthy();
          });
        }
        unmount();
        return Promise.resolve();
      }, Promise.resolve());
    });
  });

  describe('Config Options', () => {
    it('should respect enableCustomerSearch config', async () => {
      const props = {
        ...defaultProps,
        config: {
          enableCustomerSearch: false,
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should respect enableTagExtraction config', async () => {
      const props = {
        ...defaultProps,
        config: {
          enableTagExtraction: false,
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should respect enableTestMessage config', async () => {
      const props = {
        ...defaultProps,
        config: {
          enableTestMessage: false,
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      expect(screen.queryByTestId('send-test-message')).toBeNull();
    });
  });

  describe('PropTypes Validation', () => {
    it('should accept all required props without warnings', async () => {
      const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {});

      render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} />
        </TestWrapper>
      );

      // Filter out React Intl warnings about missing messages (these are expected in tests)
      const errorCalls = consoleSpy.mock.calls.filter(
        (call) => !call[0]?.includes('[React Intl]')
      );

      expect(errorCalls.length).toBe(0);
      consoleSpy.mockRestore();
    });
  });

  describe('Data Transformation Functions', () => {
    describe('preparePreviewPayload - EMAIL', () => {
      it('should build EMAIL payload with subject and body', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.EMAIL,
          formData: {
            'template-subject': 'Email Subject',
            0: {
              activeTab: 'base',
              base: {
                'template-content': '<html>Email Body</html>',
              },
            },
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        // Component should render without errors
        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });

      it('should handle EMAIL with custom values', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.EMAIL,
          formData: {
            'template-subject': 'Hello {{name}}',
            0: {
              activeTab: 'base',
              base: {
                'template-content': '<html>Hello {{name}}</html>',
              },
            },
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });

      it('should handle EMAIL with BEE editor content', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.EMAIL,
          formData: {
            'template-subject': 'Subject',
            0: {
              activeTab: 'base',
              base: {
                'template-content': '<html>BEE Content</html>',
                is_drag_drop: true,
              },
            },
          },
          beeInstance: {
            save: jest.fn(),
            onSave: jest.fn(),
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });
    });

    describe('preparePreviewPayload - SMS', () => {
      it('should build SMS payload with message', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.SMS,
          formData: {
            0: {
              'sms-editor': 'SMS message text',
            },
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });

      it('should handle SMS with activeTab structure', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.SMS,
          formData: {
            0: {
              activeTab: 'base',
              base: {
                'sms-editor': 'SMS message',
              },
            },
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });

      it('should handle SMS with custom values', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.SMS,
          formData: {
            0: {
              'sms-editor': 'Hello {{name}}',
            },
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });
    });

    describe('preparePreviewPayload - WHATSAPP', () => {
      it('should build WHATSAPP payload with template message', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.WHATSAPP,
          formData: {
            templateMsg: 'WhatsApp message',
            templateHeader: 'Header',
            templateFooter: 'Footer',
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });

      it('should handle WHATSAPP with media', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.WHATSAPP,
          formData: {
            templateMsg: 'Message',
            mediaType: 'IMAGE',
            whatsappImageSrc: 'https://image.url',
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });

      it('should handle WHATSAPP with buttons', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.WHATSAPP,
          formData: {
            templateMsg: 'Message',
            ctaData: [
              { type: 'PHONE_NUMBER', text: 'Call' },
            ],
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });

      it('should handle WHATSAPP with carousel', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.WHATSAPP,
          formData: {
            templateMsg: 'Message',
            mediaType: 'CAROUSEL',
            carouselData: [
              { bodyText: 'Item 1' },
            ],
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });
    });

    describe('preparePreviewPayload - RCS', () => {
      it('should build RCS payload with message', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.RCS,
          formData: {
            templateMessage: 'RCS message',
            templateHeader: 'RCS title',
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });

      it('should handle RCS with media', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.RCS,
          formData: {
            templateMessage: 'Message',
            rcsImageSrc: 'https://image.url',
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });

      it('should handle RCS with suggestions', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.RCS,
          formData: {
            templateMessage: 'Message',
            suggestions: [
              { type: 'QUICK_REPLY', text: 'Yes' },
            ],
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });
    });

    describe('preparePreviewPayload - INAPP', () => {
      it('should build INAPP payload with Android and iOS content', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.INAPP,
          formData: {
            androidContent: {
              templateTitle: 'Android Title',
              templateMsg: 'Android Message',
            },
            iosContent: {
              templateTitle: 'iOS Title',
              templateMsg: 'iOS Message',
            },
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });

      it('should handle INAPP with media', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.INAPP,
          formData: {
            androidContent: {
              templateTitle: 'Title',
              templateMsg: 'Message',
              mediaPreview: {
                inAppImageSrcAndroid: 'https://image.url',
              },
            },
            iosContent: {
              templateTitle: 'Title',
              templateMsg: 'Message',
              mediaPreview: {
                inAppImageSrcIos: 'https://image.url',
              },
            },
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });

      it('should handle INAPP with CTAs', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.INAPP,
          formData: {
            androidContent: {
              templateTitle: 'Title',
              templateMsg: 'Message',
              ctaData: [
                { text: 'Click Here', url: 'https://url.com' },
              ],
            },
            iosContent: {
              templateTitle: 'Title',
              templateMsg: 'Message',
              ctaData: [
                { text: 'Click Here', url: 'https://url.com' },
              ],
            },
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });
    });

    describe('preparePreviewPayload - MOBILEPUSH', () => {
      it('should build MOBILEPUSH payload with Android and iOS content', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.MOBILEPUSH,
          formData: {
            androidContent: {
              header: 'Android Header',
              bodyText: 'Android Body',
            },
            iosContent: {
              header: 'iOS Header',
              bodyText: 'iOS Body',
            },
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });

      it('should handle MOBILEPUSH with media', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.MOBILEPUSH,
          formData: {
            androidContent: {
              header: 'Header',
              bodyText: 'Body',
              bodyImage: 'https://image.url',
            },
            iosContent: {
              header: 'Header',
              bodyText: 'Body',
              bodyImage: 'https://image.url',
            },
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });

      it('should handle MOBILEPUSH with carousel', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.MOBILEPUSH,
          formData: {
            androidContent: {
              header: 'Header',
              bodyText: 'Body',
              carouselData: [
                { title: 'Item 1', message: 'Message 1' },
              ],
            },
            iosContent: {
              header: 'Header',
              bodyText: 'Body',
              carouselData: [
                { title: 'Item 1', message: 'Message 1' },
              ],
            },
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });
    });

    describe('preparePreviewPayload - VIBER', () => {
      it('should build VIBER payload with message content', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.VIBER,
          formData: {
            messageContent: 'Viber message',
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });

      it('should handle VIBER with image', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.VIBER,
          formData: {
            messageContent: 'Message',
            image: { url: 'https://image.url' },
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });

      it('should handle VIBER with video', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.VIBER,
          formData: {
            messageContent: 'Message',
            video: {
              url: 'https://video.url',
              thumbnailUrl: 'https://thumbnail.url',
            },
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });

      it('should handle VIBER with button', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.VIBER,
          formData: {
            messageContent: 'Message',
            button: {
              text: 'Click Here',
              url: 'https://url.com',
            },
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
      });
    });

    describe('preparePreviewPayload - ZALO', () => {
      it('should build ZALO payload with template configs', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.ZALO,
          formData: {
            templateId: 'template-123',
            templateName: 'Template Name',
            templatePreviewUrl: 'https://preview.url',
            templateListParams: [
              { name: 'param1', value: 'value1' },
            ],
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        // ZALO doesn't render left-panel
        await waitFor(() => {
          expect(screen.queryByTestId('left-panel')).toBeNull();
          expect(screen.getByTestId('preview-section')).toBeTruthy();
        });
      });

      it('should handle ZALO with varMapped', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.ZALO,
          formData: {
            templateId: 'template-123',
            templateName: 'Template',
            varMapped: {
              param1: 'value1',
            },
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        // ZALO doesn't render left-panel
        await waitFor(() => {
          expect(screen.queryByTestId('left-panel')).toBeNull();
          expect(screen.getByTestId('preview-section')).toBeTruthy();
        });
      });
    });

    describe('preparePreviewPayload - WEBPUSH', () => {
      it('should build WEBPUSH payload with title and message', async () => {
        const webpushContent = {
          content: {
            title: 'Push Title',
            message: 'Push message body',
          },
          accountId: 'acc-123',
          messageSubject: 'Push Title',
        };
        const props = {
          ...defaultProps,
          channel: CHANNELS.WEBPUSH,
          content: JSON.stringify(webpushContent),
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
          expect(screen.getByTestId('left-panel')).toBeTruthy();
          expect(screen.getByTestId('preview-section')).toBeTruthy();
        });
      });

      it('should handle WEBPUSH content with iconImageUrl', async () => {
        const webpushContent = {
          content: {
            title: 'Hello',
            message: 'World',
            iconImageUrl: 'https://example.com/icon.png',
          },
          accountId: 'acc-123',
        };
        const props = {
          ...defaultProps,
          channel: CHANNELS.WEBPUSH,
          content: webpushContent,
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
          expect(screen.getByTestId('preview-section')).toBeTruthy();
        });
      });

      it('should handle WEBPUSH content with cta', async () => {
        const webpushContent = {
          content: {
            title: 'Hello',
            message: 'World',
            cta: { type: 'EXTERNAL_URL', actionLink: 'https://example.com' },
          },
          accountId: 'acc-123',
        };
        const props = {
          ...defaultProps,
          channel: CHANNELS.WEBPUSH,
          content: webpushContent,
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
          expect(screen.getByTestId('preview-section')).toBeTruthy();
        });
      });

      it('should handle WEBPUSH content with expandableDetails', async () => {
        const webpushContent = {
          content: {
            title: 'Hello',
            message: 'World',
            expandableDetails: {
              media: [{ url: 'https://example.com/image.jpg', type: 'IMAGE' }],
              ctas: [{ title: 'Click', actionLink: 'https://example.com', type: 'EXTERNAL_URL' }],
            },
          },
          accountId: 'acc-123',
        };
        const props = {
          ...defaultProps,
          channel: CHANNELS.WEBPUSH,
          content: webpushContent,
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
          expect(screen.getByTestId('preview-section')).toBeTruthy();
        });
      });

      it('should handle WEBPUSH with null formData gracefully', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.WEBPUSH,
          formData: null,
          content: null,
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
          expect(screen.getByTestId('preview-section')).toBeTruthy();
        });
      });

      it('should handle WEBPUSH channel with object content (non-string)', async () => {
        const props = {
          ...defaultProps,
          channel: CHANNELS.WEBPUSH,
          content: {
            content: { title: 'ObjTitle', message: 'ObjMessage' },
            accountId: 'acc-999',
          },
        };

        render(
          <TestWrapper>
            <CommonTestAndPreview {...props} />
          </TestWrapper>
        );

        await waitFor(() => {
          expect(screen.getByTestId('preview-section')).toBeTruthy();
        });
      });
    });
  });

  describe('Tag Extraction', () => {
    it('should extract tags from EMAIL content', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.EMAIL,
        formData: {
          'template-subject': 'Hello {{name}}',
          0: {
            activeTab: 'base',
            base: {
              'template-content': '<html>Hello {{name}}, your order {{orderId}} is ready</html>',
            },
          },
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      expect(mockActions.extractTagsRequested).toHaveBeenCalled();
    });

    it('should extract tags from SMS content', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.SMS,
        formData: {
          0: {
            'sms-editor': 'Hello {{name}}, your order {{orderId}} is ready',
          },
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      expect(mockActions.extractTagsRequested).toHaveBeenCalled();
    });

    it('should handle content with only unsubscribe tag', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.EMAIL,
        formData: {
          'template-subject': 'Subject',
          0: {
            activeTab: 'base',
            base: {
              'template-content': '<html>{{unsubscribe}}</html>',
            },
          },
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });
  });

  describe('Error Handling', () => {
    it('should handle error code 7078 in updatePreviewErrors', async () => {
      const props = {
        ...defaultProps,
        updatePreviewErrors: [
          { code: 7078, message: 'Receiver Info Not found' },
        ],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // Error message should be displayed
      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle error code 7078 in fetchPrefilledValuesErrors', async () => {
      const props = {
        ...defaultProps,
        fetchPrefilledValuesErrors: [
          { code: 7078, message: 'Receiver Info Not found' },
        ],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should clear errors when customer is cleared', async () => {
      const props = {
        ...defaultProps,
        updatePreviewErrors: [
          { code: 7078, message: 'Error' },
        ],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // handleClearSelection should clear errors
      expect(mockActions.clearPreviewErrors).toBeDefined();
    });

    it('should clear errors when channel changes', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.EMAIL,
        updatePreviewErrors: [
          { code: 7078, message: 'Error' },
        ],
      };

      const { rerender } = render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      rerender(
        <TestWrapper>
          <CommonTestAndPreview {...props} channel={CHANNELS.SMS} />
        </TestWrapper>
      );

      expect(mockActions.clearPreviewErrors).toBeDefined();
    });
  });

  describe('Content Extraction', () => {
    it('should extract EMAIL content from formData', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.EMAIL,
        formData: {
          'template-subject': 'Subject',
          0: {
            activeTab: 'base',
            base: {
              'template-content': '<html>Content</html>',
            },
          },
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should extract SMS content from formData with direct path', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.SMS,
        formData: {
          0: {
            'sms-editor': 'SMS message',
          },
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should extract SMS content from formData with activeTab', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.SMS,
        formData: {
          0: {
            activeTab: 'base',
            base: {
              'sms-editor': 'SMS message',
            },
          },
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should use content prop as fallback for SMS', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.SMS,
        formData: null,
        content: 'SMS message from content prop',
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });
  });

  describe('BEE Editor Handling', () => {
    it('should handle BEE editor save', async () => {
      const beeInstance = {
        save: jest.fn(),
        onSave: jest.fn(),
      };

      const props = {
        ...defaultProps,
        channel: CHANNELS.EMAIL,
        beeInstance,
        formData: {
          'template-subject': 'Subject',
          0: {
            activeTab: 'base',
            base: {
              'template-content': '<html>Content</html>',
              is_drag_drop: true,
            },
          },
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should sync BEE content when show changes', async () => {
      const beeInstance = {
        save: jest.fn(),
        onSave: jest.fn(),
      };

      const props = {
        ...defaultProps,
        channel: CHANNELS.EMAIL,
        beeInstance,
        show: false,
        formData: {
          'template-subject': 'Subject',
          0: {
            activeTab: 'base',
            base: {
              'template-content': '<html>Content</html>',
              is_drag_drop: true,
            },
          },
        },
      };

      const { rerender } = render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // When show is false, component doesn't render content
      // Change show to true to test the sync behavior
      rerender(
        <TestWrapper>
          <CommonTestAndPreview {...props} show />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('preview-section')).toBeTruthy();
      });
    });
  });

  describe('Device Toggle', () => {
    it('should initialize device based on channel', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.SMS,
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should disable device toggle for ZALO', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.ZALO,
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      // ZALO doesn't render left-panel
      await waitFor(() => {
        expect(screen.queryByTestId('left-panel')).toBeNull();
        expect(screen.getByTestId('preview-section')).toBeTruthy();
      });
    });
  });

  describe('Customer Selection', () => {
    it('should handle customer selection', async () => {
      const props = {
        ...defaultProps,
        extractedTags: [
          { fullPath: '{{name}}', isRequired: true },
        ],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should fetch prefilled values when customer is selected', async () => {
      const props = {
        ...defaultProps,
        extractedTags: [
          { fullPath: '{{name}}', isRequired: true },
        ],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      expect(mockActions.getPrefilledValuesRequested).toBeDefined();
    });
  });

  describe('Preview Update', () => {
    it('should disable update preview when required tags are missing', async () => {
      const props = {
        ...defaultProps,
        extractedTags: [
          { fullPath: '{{name}}', isRequired: true },
        ],
        requiredTags: [
          { fullPath: '{{name}}', isRequired: true },
        ],
        customValues: {},
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should enable update preview when all required tags are filled', async () => {
      const props = {
        ...defaultProps,
        extractedTags: [
          { fullPath: '{{name}}', isRequired: true },
        ],
        requiredTags: [
          { fullPath: '{{name}}', isRequired: true },
        ],
        customValues: {
          '{{name}}': 'John',
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });
  });

  describe('Test Message', () => {
    it('should handle test message sending', async () => {
      const props = {
        ...defaultProps,
        testCustomers: [
          { userId: 'user1', name: 'User 1' },
        ],
        testGroups: [
          { groupId: 'group1', userIds: ['user1', 'user2'] },
        ],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should expand user IDs from groups', async () => {
      const props = {
        ...defaultProps,
        testGroups: [
          { groupId: 'group1', userIds: ['user1', 'user2'] },
        ],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });
  });

  describe('Complex Edge Cases', () => {
    it('should handle multiple tabs in formData', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.EMAIL,
        currentTab: 2,
        formData: {
          'template-subject': 'Subject',
          0: {
            activeTab: 'base',
            base: {
              'template-content': '<html>Tab 1</html>',
            },
          },
          1: {
            activeTab: 'base',
            base: {
              'template-content': '<html>Tab 2</html>',
            },
          },
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle missing formData fields gracefully', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.EMAIL,
        formData: {
          0: {},
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle very long content', async () => {
      const longContent = 'A'.repeat(10000);
      const props = {
        ...defaultProps,
        channel: CHANNELS.SMS,
        formData: {
          0: {
            'sms-editor': longContent,
          },
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle special characters in content', async () => {
      const props = {
        ...defaultProps,
        channel: CHANNELS.SMS,
        formData: {
          0: {
            'sms-editor': 'Message with {{name}} and {{orderId}} and special chars: @#$%^&*()',
          },
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle empty extractedTags', async () => {
      const props = {
        ...defaultProps,
        extractedTags: [],
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle null previewData', async () => {
      const props = {
        ...defaultProps,
        previewData: null,
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });

    it('should handle all config options disabled', async () => {
      const props = {
        ...defaultProps,
        config: {
          enableCustomerSearch: false,
          enableTagExtraction: false,
          enableTestMessage: false,
          enableDeviceToggle: false,
        },
      };

      render(
        <TestWrapper>
          <CommonTestAndPreview {...props} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByTestId('left-panel')).toBeTruthy();
      });
    });
  });
});
