/**
 * Integration tests for Add Test Customer flow in CommonTestAndPreview
 *
 * Tests: lookup trigger, existing/new modals, Save, toast on failure, loading states.
 * SendTestMessage and AddTestCustomerButton are NOT mocked so we can simulate clicks.
 */

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

jest.mock('html-to-text', () => ({
  convert: jest.fn((html) => (typeof html === 'string' ? html.replace(/<[^>]*>/g, '').trim() : '')),
}));

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

jest.mock('../LeftPanelContent', () => {
  const ReactLib = require('react');
  return {
    __esModule: true,
    default: function MockLeftPanelContent() {
      return ReactLib.createElement('div', { 'data-testid': 'left-panel' }, 'Left Panel');
    },
  };
});

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

jest.mock('../PreviewSection', () => {
  const ReactLib = require('react');
  return {
    __esModule: true,
    default: function MockPreviewSection() {
      return ReactLib.createElement('div', { 'data-testid': 'preview-section' }, 'Preview Section');
    },
  };
});

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

// Accordion expanded so TreeSelect and Add button are in the DOM
jest.mock('@capillarytech/cap-ui-library/CapStepsAccordian', () => {
  const ReactLib = require('react');
  return function MockCapStepsAccordian({ items }) {
    return ReactLib.createElement('div', { 'data-testid': 'cap-steps-accordian' },
      items.map((item, index) =>
        ReactLib.createElement('div', { key: item.key || index, 'data-testid': `accordion-item-${index}` },
          item.header,
          item.content)
      )
    );
  };
});

// TreeSelect mock: render search input + notFoundContent so we can type and click Add without opening a real dropdown
jest.mock('@capillarytech/cap-ui-library/CapTreeSelect', () => {
  const ReactLib = require('react');
  return function MockCapTreeSelect({ searchValue, onSearch, notFoundContent, ...rest }) {
    return ReactLib.createElement('div', { 'data-testid': 'mock-tree-select' },
      ReactLib.createElement('input', {
        'data-testid': 'tree-select-search',
        'aria-label': 'Search test customers',
        value: searchValue || '',
        onChange: (e) => onSearch && onSearch(e.target.value),
      }),
      notFoundContent
    );
  };
});

const mockGetMembersLookup = jest.fn();
const mockCreateTestCustomer = jest.fn();
jest.mock('../../../services/api', () => ({
  getMembersLookup: (...args) => mockGetMembersLookup(...args),
  createTestCustomer: (...args) => mockCreateTestCustomer(...args),
}));

const mockMessages = {
  'app.v2Components.TestAndPreviewSlidebox.testAndPreviewHeader': 'Preview and Test',
  'app.v2Components.TestAndPreviewSlidebox.addTestCustomerWithValue': 'Add {searchValue} as Test Customer',
  'app.v2Components.TestAndPreviewSlidebox.memberLookupError': 'Unable to look up customer. Please try again.',
  'app.v2Components.TestAndPreviewSlidebox.customerCreationModalTitle': 'Add new test customer',
  'app.v2Components.TestAndPreviewSlidebox.existingCustomerModalDescription': 'This user profile already exists in the system.',
  'app.v2Components.TestAndPreviewSlidebox.saveButton': 'Save',
  'app.v2Components.TestAndPreviewSlidebox.cancelButton': 'Cancel',
  'app.v2Components.TestAndPreviewSlidebox.customerEmail': 'Email',
  'app.v2Components.TestAndPreviewSlidebox.customerMobileNumber': 'Mobile Number',
  'app.v2Components.TestAndPreviewSlidebox.customerID': 'Customer ID',
  'app.v2Components.TestAndPreviewSlidebox.errorTitle': 'Error',
  'app.v2Components.TestAndPreviewSlidebox.customerAlreadyInTestList': 'This customer is already in the test customers list.',
  'app.v2Components.TestAndPreviewSlidebox.newTestCustomerAddedSuccess': 'New test customer added successfully!',
  'app.v2Components.TestAndPreviewSlidebox.failedToAddTestCustomer': 'Failed to add test customer',
  'app.v2Components.TestAndPreviewSlidebox.errorAddingTestCustomer': 'An error occurred while adding test customer',
};

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

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

describe('CommonTestAndPreview – Add Test Customer flow', () => {
  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(),
    addTestCustomer: jest.fn(),
  };

  const formatMessage = (msg) => (msg && typeof msg === 'object' && msg.id ? mockMessages[msg.id] : undefined) ?? msg?.defaultMessage ?? msg?.id ?? '';
  const defaultProps = {
    intl: { formatMessage },
    show: true,
    onClose: jest.fn(),
    channel: CHANNELS.EMAIL,
    formData: { 'template-subject': 'Test', 0: { activeTab: 'base', base: { 'template-content': '<p>Hi</p>' } } },
    content: '',
    config: { enableCustomerSearch: true, enableTagExtraction: true, enableTestMessage: 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,
  };

  beforeEach(() => {
    jest.clearAllMocks();
    Object.values(mockActions).forEach((fn) => fn.mockClear?.());
  });

  const openTreeSelectAndType = async (container, searchText) => {
    const input = screen.getByTestId('tree-select-search');
    fireEvent.change(input, { target: { value: searchText } });
    await waitFor(() => {}, { timeout: 100 });
  };

  const clickAddTestCustomer = async () => {
    const btn = await screen.findByRole('button', { name: /add.*test customer/i });
    fireEvent.click(btn);
  };

  describe('Click Add as test customer triggers lookup', () => {
    it('should call getMembersLookup with identifierType and identifierValue when Add is clicked', async () => {
      mockGetMembersLookup.mockResolvedValue({ success: true, status: {}, response: { exists: false, customerDetails: [] } });
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
        </TestWrapper>
      );
      await openTreeSelectAndType(container, 'user@example.com');
      await clickAddTestCustomer();
      await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
      expect(mockGetMembersLookup).toHaveBeenCalledWith('email', 'user@example.com');
    });
  });

  describe('Lookup returns existing customer – open Existing Customer Modal', () => {
    it('should open Existing Customer Modal with customer details when lookup returns exists=true', async () => {
      mockGetMembersLookup.mockResolvedValue({
        success: true,
        status: {},
        response: {
          exists: true,
          customerDetails: [{ firstName: 'John', lastName: 'Doe', userId: 'cust-123', identifiers: [{ type: 'email', value: 'user@example.com' }] }],
        },
      });
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
        </TestWrapper>
      );
      await openTreeSelectAndType(container, 'user@example.com');
      await clickAddTestCustomer();
      await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
      await waitFor(() => {
        expect(screen.getByText(/this user profile already exists/i)).toBeInTheDocument();
      }, { timeout: 2000 });
    });
  });

  describe('Lookup returns no customer – open New Customer Modal', () => {
    it('should open New Customer Modal when lookup returns exists=false', async () => {
      mockGetMembersLookup.mockResolvedValue({ success: true, status: {}, response: { exists: false, customerDetails: [] } });
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
        </TestWrapper>
      );
      await openTreeSelectAndType(container, 'newuser@example.com');
      await clickAddTestCustomer();
      await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
      await waitFor(() => {
        expect(screen.getByText(/add new test customer/i)).toBeInTheDocument();
      }, { timeout: 2000 });
    });
  });

  describe('Lookup failure shows toast, no modal', () => {
    it('should show error toast when getMembersLookup fails', async () => {
      const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
      mockGetMembersLookup.mockRejectedValue(new Error('Network error'));
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
        </TestWrapper>
      );
      await openTreeSelectAndType(container, 'user@example.com');
      await clickAddTestCustomer();
      await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
      await waitFor(() => expect(CapNotification.error).toHaveBeenCalled());
      // Existing-customer modal must not open on lookup failure
      expect(screen.queryByText(/this user profile already exists/i)).toBeFalsy();
    });
  });

  describe('Already in test list (before API)', () => {
    it('should show success and not call lookup when typed email is already in testCustomers', async () => {
      const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
      const testCustomersWithEmail = [
        { email: 'already@test.com', customerId: 'cust-1', userId: 'cust-1', name: 'Already', mobile: '' },
      ];
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview
            {...defaultProps}
            channel={CHANNELS.EMAIL}
            testCustomers={testCustomersWithEmail}
          />
        </TestWrapper>
      );
      await openTreeSelectAndType(container, 'already@test.com');
      await clickAddTestCustomer();
      await waitFor(() => expect(CapNotification.success).toHaveBeenCalledWith(expect.objectContaining({
        message: 'This customer is already in the test customers list.',
      })));
      expect(mockGetMembersLookup).not.toHaveBeenCalled();
    });

    it('should show success and not call lookup when typed mobile is already in testCustomers (SMS)', async () => {
      const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
      const testCustomersWithMobile = [
        { mobile: '9876543210', customerId: 'cust-2', userId: 'cust-2', name: 'Mobile', email: '' },
      ];
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview
            {...defaultProps}
            channel={CHANNELS.SMS}
            testCustomers={testCustomersWithMobile}
          />
        </TestWrapper>
      );
      await openTreeSelectAndType(container, '9876543210');
      await clickAddTestCustomer();
      await waitFor(() => expect(CapNotification.success).toHaveBeenCalledWith(expect.objectContaining({
        message: 'This customer is already in the test customers list.',
      })));
      expect(mockGetMembersLookup).not.toHaveBeenCalled();
    });
  });

  describe('Already in test list by customerId (after lookup)', () => {
    it('should show already-in-list success and not open Existing Customer modal when lookup customer is already in test list', async () => {
      const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
      // Customer in list has different email so we don't match "before API" branch; lookup returns same customerId
      const testCustomersWithCust = [
        { email: 'other@test.com', customerId: 'cust-same', userId: 'cust-same', name: 'Same', mobile: '' },
      ];
      mockGetMembersLookup.mockResolvedValue({
        success: true,
        status: {},
        response: {
          exists: true,
          customerDetails: [{
            firstName: 'Same',
            lastName: 'User',
            userId: 'cust-same',
            identifiers: [{ type: 'email', value: 'lookup@test.com' }],
          }],
        },
      });
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview
            {...defaultProps}
            channel={CHANNELS.EMAIL}
            testCustomers={testCustomersWithCust}
          />
        </TestWrapper>
      );
      await openTreeSelectAndType(container, 'lookup@test.com');
      await clickAddTestCustomer();
      await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
      await waitFor(() => expect(CapNotification.success).toHaveBeenCalledWith(expect.objectContaining({
        message: 'This customer is already in the test customers list.',
      })));
      expect(screen.queryByText(/this user profile already exists/i)).toBeFalsy();
    });
  });

  describe('Lookup throws (catch block)', () => {
    it('should show memberLookupError and not open any modal when getMembersLookup rejects', async () => {
      const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
      mockGetMembersLookup.mockRejectedValue(new Error('Network error'));
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
        </TestWrapper>
      );
      await openTreeSelectAndType(container, 'user@example.com');
      await clickAddTestCustomer();
      await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
      await waitFor(() => expect(CapNotification.error).toHaveBeenCalledWith(expect.objectContaining({
        message: 'Unable to look up customer. Please try again.',
        description: 'Unable to look up customer. Please try again.',
      })));
      expect(screen.queryByText(/add new test customer/i)).toBeFalsy();
    });
  });

  describe('Existing Customer Modal – Save calls createTestCustomer', () => {
    it('should call createTestCustomer when Save is clicked in Existing Customer Modal', async () => {
      mockGetMembersLookup.mockResolvedValue({
        success: true,
        status: {},
        response: {
          exists: true,
          customerDetails: [{ firstName: 'J', lastName: 'D', userId: 'cust-456', identifiers: [{ type: 'email', value: 'existing@example.com' }] }],
        },
      });
      mockCreateTestCustomer.mockResolvedValue({ success: true });
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
        </TestWrapper>
      );
      await openTreeSelectAndType(container, 'existing@example.com');
      await clickAddTestCustomer();
      await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
      const saveBtn = await screen.findByRole('button', { name: /save/i }, { timeout: 2000 });
      fireEvent.click(saveBtn);
      await waitFor(() => expect(mockCreateTestCustomer).toHaveBeenCalled());
      expect(mockCreateTestCustomer).toHaveBeenCalledWith(
        expect.objectContaining({ campaignUserId: 'cust-456' }),
      );
    });
  });

  describe('Existing Customer Modal – Save success closes modal and shows snackbar', () => {
    it('should close modal, show success snackbar, and add customer to test list when createTestCustomer succeeds', async () => {
      const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
      mockGetMembersLookup.mockResolvedValue({
        success: true,
        status: {},
        response: {
          exists: true,
          customerDetails: [{ firstName: 'A', lastName: 'B', userId: 'cust-789', identifiers: [{ type: 'email', value: 'success@example.com' }] }],
        },
      });
      mockCreateTestCustomer.mockResolvedValue({ success: true });
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
        </TestWrapper>
      );
      await openTreeSelectAndType(container, 'success@example.com');
      await clickAddTestCustomer();
      await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
      const saveBtn = await screen.findByRole('button', { name: /save/i }, { timeout: 2000 });
      fireEvent.click(saveBtn);
      await waitFor(() => expect(mockCreateTestCustomer).toHaveBeenCalled());
      await waitFor(() => expect(CapNotification.success).toHaveBeenCalled());
      await waitFor(() => expect(mockActions.addTestCustomer).toHaveBeenCalledWith({
        userId: 'cust-789',
        customerId: 'cust-789',
        name: 'A B',
        email: 'success@example.com',
        mobile: '',
      }));
    });
  });

  describe('Member creation failure shows toast, modal stays open', () => {
    it('should show error toast and keep modal open when createTestCustomer fails', async () => {
      const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
      mockGetMembersLookup.mockResolvedValue({
        success: true,
        status: {},
        response: {
          exists: true,
          customerDetails: [{ firstName: 'F', lastName: 'F', userId: 'cust-fail', identifiers: [{ type: 'email', value: 'fail@example.com' }] }],
        },
      });
      mockCreateTestCustomer.mockRejectedValue(new Error('Create failed'));
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
        </TestWrapper>
      );
      await openTreeSelectAndType(container, 'fail@example.com');
      await clickAddTestCustomer();
      await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
      const saveBtn = await screen.findByRole('button', { name: /save/i }, { timeout: 2000 });
      fireEvent.click(saveBtn);
      await waitFor(() => expect(CapNotification.error).toHaveBeenCalled());
    });
  });

  describe('Loading states handled correctly', () => {
    it('should show loading state during lookup and clear after response', async () => {
      let resolveLookup;
      mockGetMembersLookup.mockImplementation(() => new Promise((r) => { resolveLookup = r; }));
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
        </TestWrapper>
      );
      await openTreeSelectAndType(container, 'user@example.com');
      await clickAddTestCustomer();
      await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
      expect(resolveLookup).toBeDefined();
      resolveLookup({ success: true, status: {}, response: { exists: false, customerDetails: [] } });
      await waitFor(() => {
        expect(screen.getByText(/add new test customer/i)).toBeInTheDocument();
      });
    });
  });

  describe('SMS channel – phone sent to API', () => {
    it('should call getMembersLookup with mobile and digits when channel is SMS', async () => {
      mockGetMembersLookup.mockResolvedValue({ success: true, status: {}, response: { exists: false, customerDetails: [] } });
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.SMS} />
        </TestWrapper>
      );
      await openTreeSelectAndType(container, '9123456789');
      await clickAddTestCustomer();
      await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
      expect(mockGetMembersLookup).toHaveBeenCalledWith('mobile', '9123456789');
    });
  });

  describe('New Customer Modal – Save success', () => {
    it('should call createTestCustomer with customer payload, show success, and add new customer to test list when Save succeeds and API returns customerId', async () => {
      const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
      mockGetMembersLookup.mockResolvedValue({ success: true, status: {}, response: { exists: false, customerDetails: [] } });
      mockCreateTestCustomer.mockResolvedValue({ success: true, customerId: 'newuser@example.com' });
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
        </TestWrapper>
      );
      await openTreeSelectAndType(container, 'newuser@example.com');
      await clickAddTestCustomer();
      await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
      await waitFor(() => {
        expect(screen.getByText(/add new test customer/i)).toBeInTheDocument();
      }, { timeout: 2000 });
      const saveBtn = screen.getByRole('button', { name: /save/i });
      fireEvent.click(saveBtn);
      await waitFor(() => expect(mockCreateTestCustomer).toHaveBeenCalled());
      expect(mockCreateTestCustomer).toHaveBeenCalledWith(expect.objectContaining({
        customer: expect.objectContaining({
          email: 'newuser@example.com',
          firstName: '',
          mobile: '',
        }),
      }));
      await waitFor(() => expect(CapNotification.success).toHaveBeenCalled());
      await waitFor(() => expect(mockActions.addTestCustomer).toHaveBeenCalledWith(expect.objectContaining({
        userId: 'newuser@example.com',
        customerId: 'newuser@example.com',
        name: '',
        email: 'newuser@example.com',
        mobile: '',
      })));
    });
  });

  describe('New Customer Modal – Save API returns success: false', () => {
    it('should show error toast when createTestCustomer returns success: false', async () => {
      const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
      mockGetMembersLookup.mockResolvedValue({ success: true, status: {}, response: { exists: false, customerDetails: [] } });
      mockCreateTestCustomer.mockResolvedValue({ success: false, message: 'Server error' });
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
        </TestWrapper>
      );
      await openTreeSelectAndType(container, 'newuser@example.com');
      await clickAddTestCustomer();
      await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
      const saveBtn = await screen.findByRole('button', { name: /save/i }, { timeout: 2000 });
      fireEvent.click(saveBtn);
      await waitFor(() => expect(mockCreateTestCustomer).toHaveBeenCalled());
      await waitFor(() => expect(CapNotification.error).toHaveBeenCalledWith(expect.objectContaining({
        message: 'Error',
        description: 'Server error',
      })));
    });
  });

  describe('Lookup API error (success: false or status.isError)', () => {
    it('should show error with API message and not open any modal when lookup returns success: false (e.g. Merged customer found)', async () => {
      const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
      mockGetMembersLookup.mockResolvedValue({
        success: false,
        status: { isError: true, code: 400, message: 'Merged customer found' },
        message: 'Merged customer found',
      });
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
        </TestWrapper>
      );
      await openTreeSelectAndType(container, 'user@example.com');
      await clickAddTestCustomer();
      await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
      await waitFor(() => expect(CapNotification.error).toHaveBeenCalledWith(expect.objectContaining({
        message: 'Unable to look up customer. Please try again.',
        description: 'Merged customer found',
      })));
      expect(screen.queryByText(/add new test customer/i)).toBeFalsy();
      expect(screen.queryByText(/this user profile already exists/i)).toBeFalsy();
    });

    it('should show error and not open any modal when response has status.isError', async () => {
      const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
      mockGetMembersLookup.mockResolvedValue({
        success: true,
        status: { isError: true, message: 'Server error' },
        response: { exists: true, customerDetails: [{ userId: 'x', identifiers: [] }] },
      });
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
        </TestWrapper>
      );
      await openTreeSelectAndType(container, 'user@example.com');
      await clickAddTestCustomer();
      await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
      await waitFor(() => expect(CapNotification.error).toHaveBeenCalledWith(expect.objectContaining({
        message: 'Unable to look up customer. Please try again.',
        description: 'Server error',
      })));
      expect(screen.queryByText(/add new test customer/i)).toBeFalsy();
      expect(screen.queryByText(/this user profile already exists/i)).toBeFalsy();
    });

    it('should show fallback error message when lookup fails with no message', async () => {
      const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
      mockGetMembersLookup.mockResolvedValue({
        success: false,
        status: { isError: true },
        response: {},
      });
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
        </TestWrapper>
      );
      await openTreeSelectAndType(container, 'user@example.com');
      await clickAddTestCustomer();
      await waitFor(() => expect(CapNotification.error).toHaveBeenCalledWith(expect.objectContaining({
        message: 'Unable to look up customer. Please try again.',
        description: 'Unable to look up customer. Please try again.',
      })));
    });
  });

  describe('Existing customer with commChannels maps to customerData', () => {
    it('should map customerDetails with commChannels to customerData', async () => {
      mockGetMembersLookup.mockResolvedValue({
        success: true,
        status: {},
        response: {
          exists: true,
          customerDetails: [{
            firstName: 'Jane',
            lastName: 'Doe',
            userId: 'cust-comm',
            commChannels: [{ type: 'email', value: 'jane@example.com' }],
          }],
        },
      });
      const { container } = render(
        <TestWrapper>
          <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
        </TestWrapper>
      );
      await openTreeSelectAndType(container, 'jane@example.com');
      await clickAddTestCustomer();
      await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
      await waitFor(() => {
        const dialog = screen.getByRole('dialog');
        expect(within(dialog).getByText(/jane@example.com/i)).toBeInTheDocument();
        expect(within(dialog).getByText(/Jane Doe/i)).toBeInTheDocument();
      }, { timeout: 2000 });
    });
  });
});
