import { fireEvent, render, waitFor } from '@testing-library/react-native';
import { Platform, View } from 'react-native';
import WebView from 'react-native-webview';
import { WebViewNavigationEvent } from 'react-native-webview/lib/RNCWebViewNativeComponent';
import Logger from '../../core/logging/logger';
import { CSQWebView } from '../../webview/CSQWebView.ios';
import { registerWebView, unregisterWebView } from '../../webview/csqWebViewMethods';

jest.mock('../../core/logging/logger', () => ({
  error: jest.fn(),
  warn: jest.fn(),
}));

jest.mock('../../webview/csqWebViewMethods', () => ({
  registerWebView: jest.fn(),
  unregisterWebView: jest.fn(),
}));

jest.mock('react-native-webview', () => ({
  __esModule: true,
  default: 'WebView',
}));

describe('CSQWebView', () => {
  beforeEach(() => {
    Platform.OS = 'ios';
    jest.clearAllMocks();
    jest.resetAllMocks();
  });

  describe('Implementation 2: Child WebView', () => {
    const mockOnLoadEnd = jest.fn();

    it('should render a child webview with the correct props', () => {
      const { getByTestId } = render(
        <CSQWebView>
          <View testID="child-webview" />
        </CSQWebView>
      );

      const childWebView = getByTestId('child-webview');
      expect(childWebView).toBeTruthy();
    });

    it('should log an error if more than one child is passed', () => {
      render(
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore - Testing with multiple children
        <CSQWebView>
          <View />
          <View />
        </CSQWebView>
      );

      expect(Logger.error).toHaveBeenCalledWith(
        'CSQWebView component expects exactly 1 child, but received multiple. Ensure that only a single child element is passed'
      );
    });

    it('should inject webview on load end', () => {
      const mockEvent = {
        nativeEvent: { target: 123 },
      } as unknown as WebViewNavigationEvent;

      const { getByTestId } = render(
        <CSQWebView>
          <View testID="child-webview" />
        </CSQWebView>
      );

      const childWebView = getByTestId('child-webview');
      fireEvent(childWebView, 'loadEnd', mockEvent);

      expect(registerWebView).toHaveBeenCalledWith(123);
    });

    it('should call onLoadEnd prop from children', () => {
      const { getByTestId } = render(
        <CSQWebView>
          <WebView onLoadEnd={mockOnLoadEnd} testID="webview" />
        </CSQWebView>
      );

      const webView = getByTestId('webview');
      fireEvent(webView, 'loadEnd', { nativeEvent: { target: 123 } });

      expect(mockOnLoadEnd).toHaveBeenCalled();
    });

    it('should set applicationNameForUserAgent to "CS_WebView" when no original applicationNameForUserAgent is provided', () => {
      const { getByTestId } = render(
        <CSQWebView>
          <WebView testID="webview" />
        </CSQWebView>
      );

      const webView = getByTestId('webview');
      expect(webView.props.applicationNameForUserAgent).toContain('CS_WebView');
    });

    it('should append "CS_WebView" to existing userAgent', () => {
      const originalUserAgent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X)';

      const { getByTestId } = render(
        <CSQWebView>
          <WebView applicationNameForUserAgent={originalUserAgent} testID="webview" />
        </CSQWebView>
      );

      const webView = getByTestId('webview');
      expect(webView.props.applicationNameForUserAgent).toContain(`${originalUserAgent} CS_WebView`);
    });

    it('should work with empty string applicationNameForUserAgent', () => {
      const { getByTestId } = render(
        <CSQWebView>
          <WebView applicationNameForUserAgent="" testID="webview" />
        </CSQWebView>
      );

      const webView = getByTestId('webview');
      expect(webView.props.applicationNameForUserAgent).toContain('CS_WebView');
    });

    it('should work with undefined applicationNameForUserAgent', () => {
      const { getByTestId } = render(
        <CSQWebView>
          <WebView applicationNameForUserAgent={undefined} testID="webview" />
        </CSQWebView>
      );

      const webView = getByTestId('webview');
      expect(webView.props.applicationNameForUserAgent).toContain('CS_WebView');
    });
  });

  it('should call removeWebViewInjection on unmount', async () => {
    const { getByTestId, unmount } = render(
      <CSQWebView>
        <WebView testID="child-webview" />
      </CSQWebView>
    );

    const childWebView = getByTestId('child-webview');
    fireEvent(childWebView, 'loadEnd', {
      nativeEvent: { layout: { width: 100, height: 100 }, target: 123 },
    });

    unmount();
    await waitFor(() => expect(unregisterWebView).toHaveBeenCalled());
  });
});
