import { render } from '@testing-library/react-native';
import { Text, View } from 'react-native';
import Logger from '../../../core/logging/logger';
import CSQMethodFilter from '../../../csq/CSQMethodFilter';
import { CSQMask } from '../../../replay/csqMasking/CSQMask';

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

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

jest.mock('@contentsquare/react-native-autocapture', () => ({
  HeapIgnore: ({ children, ...props }: any) => {
    // eslint-disable-next-line @typescript-eslint/no-var-requires
    const React = require('react');
    return React.createElement(
      'View',
      {
        testID: 'heap-ignore',
        ...props,
      },
      children
    );
  },
}));

// Mock iOS codegen components
jest.mock('../../../core/specs/CSQMaskedViewNativeComponent', () => {
  // eslint-disable-next-line @typescript-eslint/no-var-requires
  const React = require('react');
  return {
    __esModule: true,
    default: React.forwardRef((props: any, ref: any) => {
      return React.createElement(
        'View',
        {
          ...props,
          ref,
          testID: 'csq-masked-view',
        },
        props.children
      );
    }),
  };
});

jest.mock('../../../core/specs/CSQUnmaskedViewNativeComponent', () => {
  // eslint-disable-next-line @typescript-eslint/no-var-requires
  const React = require('react');
  return {
    __esModule: true,
    default: React.forwardRef((props: any, ref: any) => {
      return React.createElement(
        'View',
        {
          ...props,
          ref,
          testID: 'csq-unmasked-view',
        },
        props.children
      );
    }),
  };
});

// Mock Android wrapper components
jest.mock('../../../replay/csqMasking/CSQMaskedView', () => {
  // eslint-disable-next-line @typescript-eslint/no-var-requires
  const React = require('react');
  return React.forwardRef((props: any, ref: any) => {
    return React.createElement(
      'View',
      {
        ...props,
        ref,
        testID: 'csq-masked-view',
      },
      props.children
    );
  });
});

jest.mock('../../../replay/csqMasking/CSQUnmaskedView', () => {
  // eslint-disable-next-line @typescript-eslint/no-var-requires
  const React = require('react');
  return React.forwardRef((props: any, ref: any) => {
    return React.createElement(
      'View',
      {
        ...props,
        ref,
        testID: 'csq-unmasked-view',
      },
      props.children
    );
  });
});

describe('CSQMask Component', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe('CSQMethodFilter integration', () => {
    it('should call CSQMethodFilter.warnIfDisabled on mount', () => {
      render(
        <CSQMask>
          <Text>Test</Text>
        </CSQMask>
      );

      expect(CSQMethodFilter.warnIfDisabled).toHaveBeenCalledWith(
        'CSQ',
        'CSQMask'
      );
      expect(CSQMethodFilter.warnIfDisabled).toHaveBeenCalledTimes(1);
    });
  });

  describe('Basic rendering with isSessionReplayMasked', () => {
    it('should render CSQMaskedView when isSessionReplayMasked is true', () => {
      const { getByTestId } = render(
        <CSQMask isSessionReplayMasked={true}>
          <Text>Masked Content</Text>
        </CSQMask>
      );

      expect(getByTestId('csq-masked-view')).toBeTruthy();
      expect(() => getByTestId('csq-unmasked-view')).toThrow();
    });

    it('should render CSQUnmaskedView when isSessionReplayMasked is false', () => {
      const { getByTestId } = render(
        <CSQMask isSessionReplayMasked={false}>
          <Text>Unmasked Content</Text>
        </CSQMask>
      );

      expect(getByTestId('csq-unmasked-view')).toBeTruthy();
      expect(() => getByTestId('csq-masked-view')).toThrow();
    });

    it('should default to CSQMaskedView when isSessionReplayMasked is not provided', () => {
      const { getByTestId } = render(
        <CSQMask>
          <Text>Default Content</Text>
        </CSQMask>
      );

      expect(getByTestId('csq-masked-view')).toBeTruthy();
    });
  });

  describe('HeapIgnore integration', () => {
    it('should wrap content with HeapIgnore component', () => {
      const { getByTestId } = render(
        <CSQMask>
          <Text>Test</Text>
        </CSQMask>
      );

      expect(getByTestId('heap-ignore')).toBeTruthy();
    });

    it('should pass correct HeapIgnore props when allow* props are specified', () => {
      const { getByTestId } = render(
        <CSQMask
          allowInnerHierarchy={true}
          allowProps={true}
          allowText={true}
          allowInteraction={true}
          allowAccessibilityLabel={true}
        >
          <Text>Test</Text>
        </CSQMask>
      );

      const heapIgnore = getByTestId('heap-ignore');
      expect(heapIgnore.props.allowInnerHierarchy).toBe(true);
      expect(heapIgnore.props.allowProps).toBe(true);
      expect(heapIgnore.props.allowText).toBe(true);
      expect(heapIgnore.props.allowInteraction).toBe(true);
      expect(heapIgnore.props.allowAccessibilityLabel).toBe(true);
    });

    it('should default HeapIgnore props to false when not specified', () => {
      const { getByTestId } = render(
        <CSQMask>
          <Text>Test</Text>
        </CSQMask>
      );

      const heapIgnore = getByTestId('heap-ignore');
      expect(heapIgnore.props.allowInnerHierarchy).toBe(false);
      expect(heapIgnore.props.allowProps).toBe(false);
      expect(heapIgnore.props.allowText).toBe(false);
      expect(heapIgnore.props.allowInteraction).toBe(false);
      expect(heapIgnore.props.allowAccessibilityLabel).toBe(false);
    });
  });

  describe('Children rendering', () => {
    it('should render children correctly', () => {
      const { getByText } = render(
        <CSQMask>
          <Text>Child Content</Text>
        </CSQMask>
      );

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

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

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

    it('should handle null children', () => {
      const { getByTestId } = render(<CSQMask>{null}</CSQMask>);

      expect(getByTestId('heap-ignore')).toBeTruthy();
    });
  });

  describe('Component switching', () => {
    it('should switch from masked to unmasked when isSessionReplayMasked changes', () => {
      const { getByTestId, rerender, queryByTestId } = render(
        <CSQMask isSessionReplayMasked={true}>
          <Text>Test</Text>
        </CSQMask>
      );

      expect(getByTestId('csq-masked-view')).toBeTruthy();
      expect(queryByTestId('csq-unmasked-view')).toBeNull();

      rerender(
        <CSQMask isSessionReplayMasked={false}>
          <Text>Test</Text>
        </CSQMask>
      );

      expect(getByTestId('csq-unmasked-view')).toBeTruthy();
      expect(queryByTestId('csq-masked-view')).toBeNull();
    });
  });

  describe('ignoreTextOnly mode', () => {
    it('should render children correctly', () => {
      const { getByText } = render(
        <CSQMask ignoreTextOnly={true}>
          <Text>Test Content</Text>
        </CSQMask>
      );

      expect(getByText('Test Content')).toBeTruthy();
    });

    it('should apply fixed HeapIgnore props for ignoring text', () => {
      const { getByTestId } = render(
        <CSQMask ignoreTextOnly={true}>
          <Text>Test</Text>
        </CSQMask>
      );

      const heapIgnore = getByTestId('heap-ignore');
      expect(heapIgnore.props.allowInnerHierarchy).toBe(true);
      expect(heapIgnore.props.allowProps).toBe(true);
      expect(heapIgnore.props.allowText).toBe(false);
      expect(heapIgnore.props.allowInteraction).toBe(true);
      expect(heapIgnore.props.allowAccessibilityLabel).toBe(false);
    });

    it('should use CSQMaskedView by default', () => {
      const { getByTestId } = render(
        <CSQMask ignoreTextOnly={true}>
          <Text>Test</Text>
        </CSQMask>
      );

      expect(getByTestId('csq-masked-view')).toBeTruthy();
    });

    it('should respect isSessionReplayMasked prop', () => {
      const { getByTestId } = render(
        <CSQMask ignoreTextOnly={true} isSessionReplayMasked={false}>
          <Text>Test</Text>
        </CSQMask>
      );

      expect(getByTestId('csq-unmasked-view')).toBeTruthy();
    });

    it('should ignore custom allow* props when ignoreTextOnly is true', () => {
      const { getByTestId } = render(
        <CSQMask
          ignoreTextOnly={true}
          allowText={true}
          allowInnerHierarchy={false}
          allowAccessibilityLabel={true}
        >
          <Text>Test</Text>
        </CSQMask>
      );

      const heapIgnore = getByTestId('heap-ignore');
      // Should use fixed props, not custom ones
      expect(heapIgnore.props.allowText).toBe(false);
      expect(heapIgnore.props.allowInnerHierarchy).toBe(true);
      expect(heapIgnore.props.allowAccessibilityLabel).toBe(false);
    });

    it('should log error when ignoreTextOnly is true and allow* props are set', () => {
      render(
        <CSQMask ignoreTextOnly={true} allowText={true}>
          <Text>Test</Text>
        </CSQMask>
      );

      expect(Logger.error).toHaveBeenCalledWith(
        'CSQMask: When ignoreTextOnly is true, allow* props (allowInnerHierarchy, allowProps, allowText, allowInteraction, allowAccessibilityLabel) are ignored and should not be set.'
      );
    });

    it('should log error when ignoreTextOnly is true and allowInnerHierarchy is set', () => {
      render(
        <CSQMask ignoreTextOnly={true} allowInnerHierarchy={true}>
          <Text>Test</Text>
        </CSQMask>
      );

      expect(Logger.error).toHaveBeenCalled();
    });

    it('should log error when ignoreTextOnly is true and allowProps is set', () => {
      render(
        <CSQMask ignoreTextOnly={true} allowProps={true}>
          <Text>Test</Text>
        </CSQMask>
      );

      expect(Logger.error).toHaveBeenCalled();
    });

    it('should log error when ignoreTextOnly is true and allowInteraction is set', () => {
      render(
        <CSQMask ignoreTextOnly={true} allowInteraction={false}>
          <Text>Test</Text>
        </CSQMask>
      );

      expect(Logger.error).toHaveBeenCalled();
    });

    it('should log error when ignoreTextOnly is true and allowAccessibilityLabel is set', () => {
      render(
        <CSQMask ignoreTextOnly={true} allowAccessibilityLabel={true}>
          <Text>Test</Text>
        </CSQMask>
      );

      expect(Logger.error).toHaveBeenCalled();
    });

    it('should NOT log error when ignoreTextOnly is true and no allow* props are set', () => {
      render(
        <CSQMask ignoreTextOnly={true}>
          <Text>Test</Text>
        </CSQMask>
      );

      expect(Logger.error).not.toHaveBeenCalled();
    });

    it('should NOT log error when ignoreTextOnly is false with allow* props', () => {
      render(
        <CSQMask
          ignoreTextOnly={false}
          allowText={true}
          allowInnerHierarchy={true}
        >
          <Text>Test</Text>
        </CSQMask>
      );

      expect(Logger.error).not.toHaveBeenCalled();
    });
  });
});
