/**
 * Tests for SendTestMessage Component
 *
 * Tests the component that handles sending test messages
 * @jest-environment jsdom
 */

import React from 'react';
import {
  render, screen, fireEvent, waitFor,
} from '@testing-library/react';
import { IntlProvider } from 'react-intl';
import PropTypes from 'prop-types';
import isEmpty from 'lodash/isEmpty';
// Mock cap-ui-library so SendTestMessage can load (Jest hoists mocks)
jest.mock('@capillarytech/cap-ui-library/CapRow', () => ({ children, ...rest }) => <div {...rest}>{children}</div>);
jest.mock('@capillarytech/cap-ui-library/CapButton', () => ({ children, ...rest }) => <button type="button" {...rest}>{children}</button>);
jest.mock('@capillarytech/cap-ui-library/CapHeader', () => ({ title, description }) => <div><span>{title}</span>{description}</div>);
jest.mock('@capillarytech/cap-ui-library/CapTreeSelect', () => ({ treeData, onChange, value, placeholder }) => (
  <div data-testid="cap-tree-select"><input onChange={(e) => onChange && onChange(e.target.value)} placeholder={placeholder} /></div>
));

import SendTestMessage from '../SendTestMessage';

// Mock DeliverySettings to assert props
jest.mock('../DeliverySettings', () => function MockDeliverySettings(props) {
  return (
    <div data-testid="delivery-settings" data-props={JSON.stringify({
      channel: props.channel,
      hasDeliverySettings: !!props.deliverySettings,
      senderDetailsLength: (props.senderDetailsOptions || []).length,
      wecrmAccountsLength: (props.wecrmAccounts || []).length,
      hasOnSave: typeof props.onSaveDeliverySettings === 'function',
      isLoadingSenderDetails: props.isLoadingSenderDetails,
      smsTraiDltEnabled: props.smsTraiDltEnabled,
      registeredSenderIds: props.registeredSenderIds,
      whatsappAccountFromForm: props.whatsappAccountFromForm,
    })}
    />
  );
});

// Mock CapStepsAccordian to always render content expanded
jest.mock('@capillarytech/cap-ui-library/CapStepsAccordian', () => {
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies
  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)
      ))
    );
  };
});

// Mock messages
const mockMessages = {
  testMessageDescription: {
    id: 'testMessageDescription',
    defaultMessage: 'Test out the message before sending to your customers',
  },
  sendTestMessage: {
    id: 'sendTestMessage',
    defaultMessage: 'Send Test Message',
  },
  testCustomers: {
    id: 'testCustomers',
    defaultMessage: 'Test Customers',
  },
  testCustomersPlaceholder: {
    id: 'testCustomersPlaceholder',
    defaultMessage: 'Search and select a group or individual test customers',
  },
  sendTestButton: {
    id: 'sendTestButton',
    defaultMessage: 'Send test message',
  },
};

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

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

TestWrapper.defaultProps = {
  locale: 'en',
};

describe('SendTestMessage', () => {
  const defaultProps = {
    isFetchingTestCustomers: false,
    isFetchingTestGroups: false,
    testEntitiesTreeData: [
      {
        title: 'Test Customer 1',
        value: 'customer-1',
        key: 'customer-1',
      },
      {
        title: 'Test Group 1',
        value: 'group-1',
        key: 'group-1',
        children: [
          {
            title: 'Customer in Group',
            value: 'customer-2',
            key: 'customer-2',
          },
        ],
      },
    ],
    handleTestEntitiesChange: jest.fn(),
    selectedTestEntities: [],
    handleSendTestMessage: jest.fn(),
    formData: {
      channel: 'EMAIL',
      templateId: '123',
    },
    isSendingTestMessage: false,
    formatMessage: jest.fn((msg) => msg.defaultMessage || msg.id),
    channel: 'EMAIL',
    deliverySettings: {},
    senderDetailsOptions: [],
    wecrmAccounts: [],
    onSaveDeliverySettings: jest.fn(),
    isLoadingSenderDetails: false,
    smsTraiDltEnabled: false,
    registeredSenderIds: [],
    isChannelSmsFallbackPreviewEnabled: false,
    renderAddTestCustomerButton: jest.fn(() => null),
    searchValue: '',
    setSearchValue: jest.fn(),
  };

  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe('Rendering', () => {
    it('should render SendTestMessage component', async () => {
      render(
        <TestWrapper>
          <SendTestMessage {...defaultProps} />
        </TestWrapper>
      );

      await waitFor(() => {
        expect(screen.getByText('Send Test Message')).toBeTruthy();
      });
      await waitFor(() => {
        expect(screen.getByText('Test Customers')).toBeTruthy();
      });
    });

    it('should render CapStepsAccordian with correct props', () => {
      render(
        <TestWrapper>
          <SendTestMessage {...defaultProps} />
        </TestWrapper>
      );

      // CapStepsAccordian should be rendered
      const accordion = document.querySelector('.ant-steps');
      expect(accordion || screen.getByText('Send Test Message')).toBeTruthy();
    });

    it('should render CapTreeSelect with correct props', async () => {
      const { container } = render(
        <TestWrapper>
          <SendTestMessage {...defaultProps} />
        </TestWrapper>
      );

      // CapTreeSelect should be rendered
      await waitFor(() => {
        const treeSelect = container.querySelector('.test-customers-tree-select');
        expect(treeSelect || screen.getByText('Test Customers')).toBeTruthy();
      });
    });

    it('should render send button', async () => {
      render(
        <TestWrapper>
          <SendTestMessage {...defaultProps} />
        </TestWrapper>
      );

      await waitFor(() => {
        const sendButton = screen.getByText('Send test message');
        expect(sendButton).toBeTruthy();
      });
    });
  });

  describe('DeliverySettings (sender ID / delivery settings)', () => {
    it('should render DeliverySettings when channel is SMS', () => {
      render(
        <TestWrapper>
          <SendTestMessage {...defaultProps} channel="SMS" />
        </TestWrapper>
      );
      const el = screen.getByTestId('delivery-settings');
      expect(el).toBeTruthy();
      const data = JSON.parse(el.getAttribute('data-props'));
      expect(data.channel).toBe('SMS');
      expect(data.hasOnSave).toBe(true);
    });

    it('should render DeliverySettings when channel is EMAIL', () => {
      render(
        <TestWrapper>
          <SendTestMessage {...defaultProps} channel="EMAIL" />
        </TestWrapper>
      );
      expect(screen.getByTestId('delivery-settings')).toBeTruthy();
    });

    it('should render DeliverySettings when channel is WHATSAPP', () => {
      render(
        <TestWrapper>
          <SendTestMessage {...defaultProps} channel="WHATSAPP" />
        </TestWrapper>
      );
      expect(screen.getByTestId('delivery-settings')).toBeTruthy();
    });

    it('should not render DeliverySettings when channel is INAPP', () => {
      render(
        <TestWrapper>
          <SendTestMessage {...defaultProps} channel="INAPP" />
        </TestWrapper>
      );
      expect(screen.queryByTestId('delivery-settings')).toBeNull();
    });

    it('should pass whatsappAccountFromForm when channel is WHATSAPP and formData has accountName', () => {
      render(
        <TestWrapper>
          <SendTestMessage
            {...defaultProps}
            channel="WHATSAPP"
            formData={{ ...defaultProps.formData, accountName: 'My WABA' }}
          />
        </TestWrapper>
      );
      const el = screen.getByTestId('delivery-settings');
      const data = JSON.parse(el.getAttribute('data-props'));
      expect(data.whatsappAccountFromForm).toEqual({ accountName: 'My WABA' });
    });

    it('should pass whatsappAccountFromForm undefined when channel is WHATSAPP and formData has no accountName', () => {
      render(
        <TestWrapper>
          <SendTestMessage
            {...defaultProps}
            channel="WHATSAPP"
            formData={{ ...defaultProps.formData, accountName: undefined }}
          />
        </TestWrapper>
      );
      const el = screen.getByTestId('delivery-settings');
      const data = JSON.parse(el.getAttribute('data-props'));
      expect(data.whatsappAccountFromForm).toBeUndefined();
    });

    it('should pass delivery props to DeliverySettings', () => {
      const onSave = jest.fn();
      render(
        <TestWrapper>
          <SendTestMessage
            {...defaultProps}
            channel="SMS"
            deliverySettings={{ domainId: 1 }}
            senderDetailsOptions={[{ domainId: 1, domainName: 'SMS Dom' }]}
            wecrmAccounts={[]}
            onSaveDeliverySettings={onSave}
            isLoadingSenderDetails={true}
            smsTraiDltEnabled
            registeredSenderIds={['ID1']}
          />
        </TestWrapper>
      );
      const el = screen.getByTestId('delivery-settings');
      const data = JSON.parse(el.getAttribute('data-props'));
      expect(data.hasDeliverySettings).toBe(true);
      expect(data.senderDetailsLength).toBe(1);
      expect(data.wecrmAccountsLength).toBe(0);
      expect(data.hasOnSave).toBe(true);
      expect(data.isLoadingSenderDetails).toBe(true);
      expect(data.smsTraiDltEnabled).toBe(true);
      expect(data.registeredSenderIds).toEqual(['ID1']);
    });
  });

  describe('Loading States', () => {
    it('should show loading when fetching test customers', () => {
      const props = {
        ...defaultProps,
        isFetchingTestCustomers: true,
      };

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

      // TreeSelect should show loading state
      expect(defaultProps.formatMessage).toHaveBeenCalled();
    });

    it('should show loading when fetching test groups', () => {
      const props = {
        ...defaultProps,
        isFetchingTestGroups: true,
      };

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

      // TreeSelect should show loading state
      expect(defaultProps.formatMessage).toHaveBeenCalled();
    });

    it('should show loading when fetching both', () => {
      const props = {
        ...defaultProps,
        isFetchingTestCustomers: true,
        isFetchingTestGroups: true,
      };

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

      expect(defaultProps.formatMessage).toHaveBeenCalled();
    });
  });

  describe('TreeSelect Functionality', () => {
    it('should pass treeData to CapTreeSelect', () => {
      render(
        <TestWrapper>
          <SendTestMessage {...defaultProps} />
        </TestWrapper>
      );

      // TreeSelect should receive treeData
      expect(defaultProps.testEntitiesTreeData).toBeDefined();
    });

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

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

      await waitFor(() => {
        expect(screen.getByText('Send test message')).toBeTruthy();
      });
    });

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

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

      await waitFor(() => {
        expect(screen.getByText('Send test message')).toBeTruthy();
      });
    });

    it('should call handleTestEntitiesChange when selection changes', () => {
      render(
        <TestWrapper>
          <SendTestMessage {...defaultProps} />
        </TestWrapper>
      );

      // Simulate tree select change (if possible)
      // Note: Actual interaction depends on CapTreeSelect implementation
      expect(defaultProps.handleTestEntitiesChange).toBeDefined();
    });
  });

  describe('Send Button', () => {
    it('should call handleSendTestMessage when button is clicked', async () => {
      const props = {
        ...defaultProps,
        selectedTestEntities: ['customer-1'],
      };

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

      await waitFor(() => {
        const sendButton = screen.getByText('Send test message');
        expect(sendButton).toBeTruthy();
      });

      const sendButton = screen.getByText('Send test message');
      fireEvent.click(sendButton);

      expect(defaultProps.handleSendTestMessage).toHaveBeenCalled();
    });

    it('should disable button when no entities are selected', async () => {
      const props = {
        ...defaultProps,
        selectedTestEntities: [],
      };

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

      await waitFor(() => {
        const sendButton = screen.getByText('Send test message');
        expect(sendButton).toBeTruthy();
      });
      // Button should be disabled when isEmpty(selectedTestEntities) is true
      expect(isEmpty(props.selectedTestEntities)).toBe(true);
    });

    it('should disable button when isSendingTestMessage is true', async () => {
      const props = {
        ...defaultProps,
        selectedTestEntities: ['customer-1'],
        isSendingTestMessage: true,
      };

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

      await waitFor(() => {
        const sendButton = screen.getByText('Send test message');
        expect(sendButton).toBeTruthy();
      });
      // Button should be disabled when isSendingTestMessage is true
      expect(props.isSendingTestMessage).toBe(true);
    });

    it('should enable button when entities are selected and not sending', async () => {
      const props = {
        ...defaultProps,
        selectedTestEntities: ['customer-1', 'group-1'],
        isSendingTestMessage: false,
      };

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

      await waitFor(() => {
        const sendButton = screen.getByText('Send test message');
        expect(sendButton).toBeTruthy();
      });
      expect(isEmpty(props.selectedTestEntities)).toBe(false);
      expect(props.isSendingTestMessage).toBe(false);
    });
  });

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

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

      await waitFor(() => {
        expect(screen.getByText('Send test message')).toBeTruthy();
      });
    });

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

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

      await waitFor(() => {
        expect(screen.getByText('Send test message')).toBeTruthy();
      });
    });

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

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

      await waitFor(() => {
        expect(screen.getByText('Send test message')).toBeTruthy();
      });
    });

    it('should handle complex treeData structure', async () => {
      const complexTreeData = [
        {
          title: 'Group 1',
          value: 'group-1',
          key: 'group-1',
          children: [
            {
              title: 'Sub Group 1',
              value: 'subgroup-1',
              key: 'subgroup-1',
              children: [
                {
                  title: 'Customer 1',
                  value: 'customer-1',
                  key: 'customer-1',
                },
              ],
            },
          ],
        },
      ];

      const props = {
        ...defaultProps,
        testEntitiesTreeData: complexTreeData,
      };

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

      await waitFor(() => {
        expect(screen.getByText('Send test message')).toBeTruthy();
      });
    });

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

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

      await waitFor(() => {
        expect(screen.getByText('Send test message')).toBeTruthy();
      });
    });

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

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

      await waitFor(() => {
        expect(screen.getByText('Send test message')).toBeTruthy();
      });
    });
  });

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

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

      expect(consoleSpy).not.toHaveBeenCalled();
      consoleSpy.mockRestore();
    });
  });

  describe('notFoundContent (Add as test customer)', () => {
    it('should call renderAddTestCustomerButton and use result as notFoundContent', () => {
      const renderAddTestCustomerButton = jest.fn(() => (
        <button type="button" data-testid="add-test-customer-btn">
          Add as test customer
        </button>
      ));
      const props = {
        ...defaultProps,
        renderAddTestCustomerButton,
      };
      render(
        <TestWrapper>
          <SendTestMessage {...props} />
        </TestWrapper>
      );
      expect(renderAddTestCustomerButton).toHaveBeenCalled();
    });

    it('should render notFoundContent as a clickable button when provided', () => {
      const onAddClick = jest.fn();
      const renderAddTestCustomerButton = jest.fn(() => (
        <button type="button" data-testid="add-test-customer-btn" onClick={onAddClick}>
          Add as test customer
        </button>
      ));
      const props = {
        ...defaultProps,
        renderAddTestCustomerButton,
      };
      render(
        <TestWrapper>
          <SendTestMessage {...props} />
        </TestWrapper>
      );
      // Assert component wiring: renderAddTestCustomerButton must have been called during render.
      expect(renderAddTestCustomerButton).toHaveBeenCalled();
      // Assert the returned element has the expected shape.
      const notFoundContent = renderAddTestCustomerButton.mock.results[0].value;
      expect(notFoundContent).toBeTruthy();
      expect(notFoundContent.type).toBe('button');
      expect(notFoundContent.props['data-testid']).toBe('add-test-customer-btn');
      // Assert clicking the button triggers the handler.
      notFoundContent.props.onClick();
      expect(onAddClick).toHaveBeenCalled();
    });
  });
});
