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

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

export function PointerEventsTest() {
  return (
    <TestSuite name="pointer events">
      <TestCase
        itShould="call inner and outer view when pressing inner"
        initialState={{ inner: false, outer: false, outerContainer: false }}
        arrange={({ setState, reset }) => {
          return (
            <PointerEventsView
              pointerEventsOuter="auto"
              setState={setState}
              reset={reset}
            />
          );
        }}
        assert={({ expect, state }) => {
          expect(state).to.be.deep.eq({
            inner: true,
            outer: true,
            outerContainer: true,
          });
        }}
      />
      <TestCase
        //it seems there's a bug on Android, which causes pointerEvents to not work correctly for ScrollViews
        skip={Platform.select({
          android: 'known bug',
          harmony: 'fails on Android',
        })} // https://gl.swmansion.com/rnoh/react-native-harmony/-/issues/424
        itShould="call only outer when pressing inner view"
        initialState={{ inner: false, outer: false, outerContainer: true }}
        arrange={({ setState, reset }) => {
          return (
            <PointerEventsView
              pointerEventsOuter="box-only"
              setState={setState}
              reset={reset}
            />
          );
        }}
        assert={({ expect, state }) => {
          expect(state).to.be.deep.eq({
            inner: false,
            outer: true,
            outerContainer: true,
          });
        }}
      />
      <TestCase
        //it seems there's a bug on Android, which causes pointerEvents to not work correctly for ScrollViews
        skip={Platform.select({
          android: 'known bug',
        })}
        itShould="call inner and outer only when pressing inner view"
        initialState={{ inner: false, outer: false, outerContainer: false }}
        arrange={({ setState, reset }) => {
          return (
            <PointerEventsView
              disableOuterContainerTouch
              pointerEventsOuter="box-none"
              setState={setState}
              reset={reset}
            />
          );
        }}
        assert={({ expect, state }) => {
          expect(state.inner).to.be.true;
          expect(state.outer).to.be.true;
        }}
      />
      <TestCase
        //it seems there's a bug on Android, which causes pointerEvents to not work correctly for ScrollViews
        skip={Platform.select({
          android: 'known bug',
        })}
        itShould="not call inner or outer when pressing inner or outer views"
        initialState={{ inner: false, outer: false, outerContainer: false }}
        arrange={({ setState, reset }) => {
          return (
            <PointerEventsView
              pointerEventsOuter="none"
              setState={setState}
              reset={reset}
            />
          );
        }}
        assert={({ expect, state }) => {
          expect(state).to.be.deep.eq({
            inner: false,
            outer: false,
            outerContainer: true,
          });
        }}
      />
    </TestSuite>
  );
}

function PointerEventsView(props: {
  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;
    }>
  >;
  reset: () => void;
}) {
  return (
    <View style={{ height: 100, width: '100%', flexDirection: 'row' }}>
      <View
        style={{ backgroundColor: 'red' }}
        onTouchEnd={
          props.disableOuterContainerTouch
            ? undefined
            : () => {
              props.setState(prev => ({ ...prev, outerContainer: true }));
            }
        }>
        <ScrollView
          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>
  );
}