import { render } from '@testing-library/react-native';
import { Text, View } from 'react-native';
import { CSMask } from '../../../replay/masking/CSMask.ios';

// Import the specific iOS version directly

// Mock CSQMethodFilter
jest.mock('../../../csq/CSQMethodFilter', () => ({
  __esModule: true,
  default: {
    warnIfDisabled: jest.fn(),
  },
}));

// Mock the CSMaskedView and CSUnmaskedView components
jest.mock('../../../core/specs/CSMaskedViewNativeComponent', () => {
  const React = require('react');
  return React.forwardRef((props, ref) => {
    return React.createElement(
      'View',
      {
        ...props,
        ref,
        testID: 'CSMaskedViewNativeComponent',
        'data-original-testid': props.testID, // Preserve original testID for assertions
      },
      props.children
    );
  });
});

jest.mock('../../../core/specs/CSUnmaskedViewNativeComponent', () => {
  const React = require('react');
  return React.forwardRef((props, ref) => {
    return React.createElement(
      'View',
      {
        ...props,
        ref,
        testID: 'CSUnmaskedViewNativeComponent',
        'data-original-testid': props.testID, // Preserve original testID for assertions
      },
      props.children
    );
  });
});

describe('CSMask.ios', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe('rendering behavior', () => {
    it('should render CSMaskedViewNativeComponent when isMasking is true', () => {
      const { getByTestId } = render(
        <CSMask isMasking={true} testID="cs-mask">
          <Text>Test Child</Text>
        </CSMask>
      );

      expect(getByTestId('CSMaskedViewNativeComponent')).toBeTruthy();
    });

    it('should render CSUnmaskedViewNativeComponent when isMasking is false', () => {
      const { getByTestId } = render(
        <CSMask isMasking={false} testID="cs-mask">
          <Text>Test Child</Text>
        </CSMask>
      );

      expect(getByTestId('CSUnmaskedViewNativeComponent')).toBeTruthy();
    });

    it('should default to masked view when isMasking is not provided', () => {
      const { getByTestId } = render(
        <CSMask testID="cs-mask">
          <Text>Test Child</Text>
        </CSMask>
      );

      expect(getByTestId('CSMaskedViewNativeComponent')).toBeTruthy();
    });
  });

  describe('props forwarding', () => {
    it('should forward all props to the masked component', () => {
      const testProps = {
        isMasking: true,
        testID: 'test-id',
        style: { backgroundColor: 'red' },
        customProp: 'custom-value',
      };

      const { getByTestId } = render(
        <CSMask {...testProps}>
          <Text>Test Child</Text>
        </CSMask>
      );

      const maskedComponent = getByTestId('CSMaskedViewNativeComponent');
      expect(maskedComponent).toBeTruthy();
      expect(maskedComponent.props['data-original-testid']).toBe('test-id');
      expect(maskedComponent.props.style).toEqual({ backgroundColor: 'red' });
      expect(maskedComponent.props.customProp).toBe('custom-value');
    });

    it('should forward all props to the unmasked component', () => {
      const testProps = {
        isMasking: false,
        testID: 'test-id',
        style: { backgroundColor: 'blue' },
        customProp: 'custom-value',
      };

      const { getByTestId } = render(
        <CSMask {...testProps}>
          <Text>Test Child</Text>
        </CSMask>
      );

      const unmaskedComponent = getByTestId('CSUnmaskedViewNativeComponent');
      expect(unmaskedComponent).toBeTruthy();
      expect(unmaskedComponent.props['data-original-testid']).toBe('test-id');
      expect(unmaskedComponent.props.style).toEqual({
        backgroundColor: 'blue',
      });
      expect(unmaskedComponent.props.customProp).toBe('custom-value');
    });

    it('should not forward isMasking prop to native components', () => {
      const { getByTestId } = render(
        <CSMask isMasking={true} testID="test-id">
          <Text>Test Child</Text>
        </CSMask>
      );

      const maskedComponent = getByTestId('CSMaskedViewNativeComponent');
      expect(maskedComponent.props.isMasking).toBeUndefined();
    });
  });

  describe('children rendering', () => {
    it('should render children in masked component', () => {
      const { getByTestId, getByText } = render(
        <CSMask isMasking={true} testID="cs-mask">
          <Text>Child Content</Text>
        </CSMask>
      );

      expect(getByTestId('CSMaskedViewNativeComponent')).toBeTruthy();
      expect(getByText('Child Content')).toBeTruthy();
    });

    it('should render children in unmasked component', () => {
      const { getByTestId, getByText } = render(
        <CSMask isMasking={false} testID="cs-mask">
          <Text>Child Content</Text>
        </CSMask>
      );

      expect(getByTestId('CSUnmaskedViewNativeComponent')).toBeTruthy();
      expect(getByText('Child Content')).toBeTruthy();
    });

    it('should render multiple children', () => {
      const { getByText } = render(
        <CSMask isMasking={true}>
          <Text>First Child</Text>
          <Text>Second Child</Text>
          <View>
            <Text>Nested Child</Text>
          </View>
        </CSMask>
      );

      expect(getByText('First Child')).toBeTruthy();
      expect(getByText('Second Child')).toBeTruthy();
      expect(getByText('Nested Child')).toBeTruthy();
    });

    it('should handle no children gracefully', () => {
      const { getByTestId } = render(
        <CSMask isMasking={true} testID="cs-mask">
          {null}
        </CSMask>
      );

      expect(getByTestId('CSMaskedViewNativeComponent')).toBeTruthy();
    });
  });

  describe('component switching', () => {
    it('should switch from masked to unmasked when isMasking changes', () => {
      const { getByTestId, rerender, queryByTestId } = render(
        <CSMask isMasking={true} testID="cs-mask">
          <Text>Test Child</Text>
        </CSMask>
      );

      // Initially masked
      expect(getByTestId('CSMaskedViewNativeComponent')).toBeTruthy();
      expect(queryByTestId('CSUnmaskedViewNativeComponent')).toBeNull();

      // Switch to unmasked
      rerender(
        <CSMask isMasking={false} testID="cs-mask">
          <Text>Test Child</Text>
        </CSMask>
      );

      expect(getByTestId('CSUnmaskedViewNativeComponent')).toBeTruthy();
      expect(queryByTestId('CSMaskedViewNativeComponent')).toBeNull();
    });

    it('should switch from unmasked to masked when isMasking changes', () => {
      const { getByTestId, rerender, queryByTestId } = render(
        <CSMask isMasking={false} testID="cs-mask">
          <Text>Test Child</Text>
        </CSMask>
      );

      // Initially unmasked
      expect(getByTestId('CSUnmaskedViewNativeComponent')).toBeTruthy();
      expect(queryByTestId('CSMaskedViewNativeComponent')).toBeNull();

      // Switch to masked
      rerender(
        <CSMask isMasking={true} testID="cs-mask">
          <Text>Test Child</Text>
        </CSMask>
      );

      expect(getByTestId('CSMaskedViewNativeComponent')).toBeTruthy();
      expect(queryByTestId('CSUnmaskedViewNativeComponent')).toBeNull();
    });
  });

  describe('edge cases', () => {
    it('should handle undefined isMasking prop', () => {
      const { getByTestId } = render(
        <CSMask isMasking={undefined} testID="cs-mask">
          <Text>Test Child</Text>
        </CSMask>
      );

      // Should default to true (masked)
      expect(getByTestId('CSMaskedViewNativeComponent')).toBeTruthy();
    });

    it('should handle null isMasking prop', () => {
      const { getByTestId } = render(
        <CSMask isMasking={null as any} testID="cs-mask">
          <Text>Test Child</Text>
        </CSMask>
      );

      // Should render unmasked (falsy value)
      expect(getByTestId('CSUnmaskedViewNativeComponent')).toBeTruthy();
    });

    it('should handle truthy non-boolean values', () => {
      const { getByTestId } = render(
        <CSMask isMasking={'true' as any} testID="cs-mask">
          <Text>Test Child</Text>
        </CSMask>
      );

      // Should render masked (truthy value)
      expect(getByTestId('CSMaskedViewNativeComponent')).toBeTruthy();
    });

    it('should handle falsy non-boolean values', () => {
      const { getByTestId } = render(
        <CSMask isMasking={0 as any} testID="cs-mask">
          <Text>Test Child</Text>
        </CSMask>
      );

      // Should render unmasked (falsy value)
      expect(getByTestId('CSUnmaskedViewNativeComponent')).toBeTruthy();
    });
  });

  describe('accessibility and testID', () => {
    it('should pass through accessibility props to masked component', () => {
      const { getByTestId } = render(
        <CSMask
          isMasking={true}
          testID="cs-mask"
          accessibilityLabel="Masked content"
          accessibilityHint="This content is masked"
        >
          <Text>Test Child</Text>
        </CSMask>
      );

      const maskedComponent = getByTestId('CSMaskedViewNativeComponent');
      expect(maskedComponent.props.accessibilityLabel).toBe('Masked content');
      expect(maskedComponent.props.accessibilityHint).toBe(
        'This content is masked'
      );
    });

    it('should pass through accessibility props to unmasked component', () => {
      const { getByTestId } = render(
        <CSMask
          isMasking={false}
          testID="cs-mask"
          accessibilityLabel="Unmasked content"
          accessibilityHint="This content is unmasked"
        >
          <Text>Test Child</Text>
        </CSMask>
      );

      const unmaskedComponent = getByTestId('CSUnmaskedViewNativeComponent');
      expect(unmaskedComponent.props.accessibilityLabel).toBe(
        'Unmasked content'
      );
      expect(unmaskedComponent.props.accessibilityHint).toBe(
        'This content is unmasked'
      );
    });
  });

  describe('performance', () => {
    it('should not re-render children when isMasking changes', () => {
      const ChildComponent = jest.fn(() => <Text>Child</Text>);

      const { rerender } = render(
        <CSMask isMasking={true}>
          <ChildComponent />
        </CSMask>
      );

      expect(ChildComponent).toHaveBeenCalledTimes(1);

      rerender(
        <CSMask isMasking={false}>
          <ChildComponent />
        </CSMask>
      );

      // Child should re-render because it's moved to a different component
      expect(ChildComponent).toHaveBeenCalledTimes(2);
    });
  });
});
