/**
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import {TestSuite} from '@rnoh/testerino';
import {Platform, ScrollView, View} from 'react-native';
import {getScrollViewContent} from './fixtures';
import {Button} from '../../components';
import {TestCase} from '../../components/TestCase';
import {createRef, forwardRef} from 'react';
import {useEnvironment} from '../../contexts';

export function PointerEventsTest() {
  const {
    env: {driver},
  } = useEnvironment();

  return (
    <TestSuite name="pointer events">
      <TestCase.Automated
        itShould="call inner and outer view when pressing inner"
        tags={['sequential']}
        initialState={{
          inner: false,
          outer: false,
          outerContainer: false,
          scrollViewRef: createRef<React.ElementRef<typeof ScrollView>>(),
        }}
        arrange={({setState, state, done, reset}) => {
          return (
            <PointerEventsView
              pointerEventsOuter="auto"
              setState={props => {
                setState(props);
                done();
              }}
              reset={reset}
              ref={state.scrollViewRef}
            />
          );
        }}
        act={async ({state}) => {
          await driver?.click({ref: state.scrollViewRef});
        }}
        assert={({expect, state}) => {
          expect(state).to.include({
            inner: true,
            outer: true,
            outerContainer: true,
          });
        }}
      />
      <TestCase.Automated
        //it seems there's a bug on Android, which causes pointerEvents to not work correctly for ScrollViews
        skip={Platform.select({
          android: 'known bug',
        })}
        tags={['sequential']}
        itShould="call only outer when pressing inner view"
        initialState={{
          inner: false,
          outer: false,
          outerContainer: true,
          scrollViewRef: createRef<React.ElementRef<typeof ScrollView>>(),
        }}
        arrange={({setState, state, done, reset}) => {
          return (
            <PointerEventsView
              pointerEventsOuter="box-only"
              ref={state.scrollViewRef}
              setState={props => {
                setState(props);
                done();
              }}
              reset={reset}
            />
          );
        }}
        act={async ({state}) => {
          await driver?.click({ref: state.scrollViewRef});
        }}
        assert={({expect, state}) => {
          expect(state).to.include({
            inner: false,
            outer: true,
            outerContainer: true,
          });
        }}
      />
      <TestCase.Automated
        //it seems there's a bug on Android, which causes pointerEvents to not work correctly for ScrollViews
        skip={Platform.select({
          android: 'known bug',
        })}
        tags={['sequential']}
        itShould="call inner and outer only when pressing inner view"
        initialState={{
          inner: false,
          outer: false,
          outerContainer: true,
          scrollViewRef: createRef<React.ElementRef<typeof ScrollView>>(),
        }}
        arrange={({setState, reset, state, done}) => {
          return (
            <PointerEventsView
              disableOuterContainerTouch
              pointerEventsOuter="box-none"
              ref={state.scrollViewRef}
              setState={props => {
                setState(props);
                done();
              }}
              reset={reset}
            />
          );
        }}
        act={async ({state}) => {
          await driver?.click({ref: state.scrollViewRef});
        }}
        assert={({expect, state}) => {
          expect(state.inner).to.be.true;
          expect(state.outer).to.be.true;
        }}
      />
      <TestCase.Automated
        //it seems there's a bug on Android, which causes pointerEvents to not work correctly for ScrollViews
        skip={{android: true, harmony: true}}
        itShould="not call inner or outer when pressing inner or outer views"
        tags={['sequential']}
        initialState={{
          inner: false,
          outer: false,
          outerContainer: true,
          scrollViewRef: createRef<React.ElementRef<typeof ScrollView>>(),
        }}
        arrange={({setState, reset, state, done}) => {
          return (
            <PointerEventsView
              pointerEventsOuter="none"
              ref={state.scrollViewRef}
              setState={props => {
                setState(props);
                done();
              }}
              reset={reset}
            />
          );
        }}
        act={async ({state}) => {
          await driver?.click({ref: state.scrollViewRef});
        }}
        assert={({expect, state}) => {
          expect(state).to.be.deep.eq({
            inner: false,
            outer: false,
            outerContainer: true,
          });
        }}
      />
    </TestSuite>
  );
}

const PointerEventsView = forwardRef<
  ScrollView,
  {
    disableOuterContainerTouch?: boolean;
    pointerEventsOuter?: 'box-none' | 'none' | 'box-only' | 'auto';
    pointerEventsInner?: 'box-none' | 'none' | 'box-only' | 'auto';
    setState: React.Dispatch<
      React.SetStateAction<{
        inner: boolean;
        outer: boolean;
        outerContainer: boolean;
        scrollViewRef: React.RefObject<ScrollView | null>; // Added this to match TestCase.Automated
      }>
    >;
    reset: () => void;
  }
>((props, ref) => {
  return (
    <View style={{height: 100, width: '100%', flexDirection: 'row'}}>
      <View
        style={{backgroundColor: 'red'}}
        onTouchEnd={
          props.disableOuterContainerTouch
            ? undefined
            : () => {
                props.setState(prev => ({...prev, outerContainer: true}));
              }
        }>
        <ScrollView
          ref={ref}
          nestedScrollEnabled
          style={{
            height: 100,
            width: 100,
            backgroundColor: 'green',
            padding: 20,
          }}
          pointerEvents={props.pointerEventsOuter}
          onTouchEnd={() => {
            props.setState(prev => ({...prev, outer: true}));
          }}>
          {getScrollViewContent({
            amountOfChildren: 3,
            onTouchEnd: () => {
              props.setState(prev => ({...prev, inner: true}));
            },
            pointerEvents: props.pointerEventsInner,
          })}
        </ScrollView>
      </View>
      <Button label="reset" onPress={props.reset} />
    </View>
  );
});