import { View } from 'react-native';
import { ContentsquareModule } from '../../core/nativeModules';
import {
  hasOnlyOneChild,
  initComponents,
  mergeCallbacks,
} from '../../utils/utils';

jest.mock('../../core/nativeModules', () => ({
  ContentsquareModule: {
    initComponents: jest.fn(),
  },
}));

jest.mock('react-native', () => ({
  Platform: {
    constants: {
      reactNativeVersion: {
        major: 0,
        minor: 64,
        patch: 3,
      },
    },
  },
}));

jest.mock('../../../package.json', () => ({
  version: '1.2.3',
}));

describe('initComponents', () => {
  it('should initialize components with correct parameters', () => {
    initComponents();

    const expectedReactNativeVersion = '0.64.3';

    expect(ContentsquareModule.initComponents).toHaveBeenCalledWith({
      xpf_type: 'reactnative',
      xpf_version: expectedReactNativeVersion,
      xpf_bridge_version: '1.2.3',
    });
    expect(ContentsquareModule.initComponents).toHaveBeenCalledTimes(1);
  });
});

describe('hasOnlyOneChild', () => {
  it('should return true if there is exactly one child', () => {
    const singleChild = <View />;

    const result = hasOnlyOneChild(singleChild);

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

  it('should return false if there are multiple children', () => {
    const multipleChildren = [
      <View key="1">Child 1</View>,
      <View key="2">Child 2</View>,
    ];

    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore - Testing invalid input with multiple elements
    const result = hasOnlyOneChild(multipleChildren);

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

  it('should return false if there are no children', () => {
    const result = hasOnlyOneChild(undefined);

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

describe('mergeCallbacks', () => {
  it('should call both internal and user callbacks', () => {
    const internalCallback = jest.fn();
    const userCallback = jest.fn();

    const mergedCallback = mergeCallbacks(internalCallback, userCallback);
    mergedCallback('arg1', 'arg2');

    expect(internalCallback).toHaveBeenCalledWith('arg1', 'arg2');
    expect(userCallback).toHaveBeenCalledWith('arg1', 'arg2');
  });

  it('should call only internal callback if user callback is not provided', () => {
    const internalCallback = jest.fn();

    const mergedCallback = mergeCallbacks(internalCallback, undefined);
    mergedCallback('arg1', 'arg2');

    expect(internalCallback).toHaveBeenCalledWith('arg1', 'arg2');
  });
});
