/**
 * 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 {
  StyleSheet,
  Text,
  TouchableWithoutFeedback,
  View,
  findNodeHandle,
} from 'react-native';
import {TestSuite} from '@rnoh/testerino';
import React, {createRef, useRef, useState} from 'react';
import {Button, TestCase} from '../../components';
import {ViewAccessibilityTest} from './ViewAccessibilityTest';
import {useEnvironment} from '../../contexts';

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

  return (
    <TestSuite name="View">
      <TestCase.Example
        modal
        itShould="log the descriptor on the native side when 'debug' hint is provided">
        <View
          id="__harmony::debug:sampleNativeId"
          style={{width: 64, height: 64, backgroundColor: 'red'}}
        />
      </TestCase.Example>
      <TestCase.Example modal itShould="apply testId to view">
        <View
          testID="testId"
          style={{width: 64, height: 64, backgroundColor: 'red'}}
        />
      </TestCase.Example>
      <TestCase.Example itShould="render square with transparent background on gray background">
        <View style={{width: '100%', height: 100, backgroundColor: 'gray'}}>
          <View
            style={{
              width: 200,
              height: 100,
              borderWidth: 1,
              borderColor: '#FF00FF',
            }}
          />
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="render square with rounded corners with different radii (left/right)">
        <View style={{width: '100%', height: 100, backgroundColor: 'gray'}}>
          <View
            style={{
              width: 100,
              height: 100,
              borderWidth: 3,
              borderColor: 'white',
              borderTopLeftRadius: 10,
              borderTopRightRadius: 20,
              borderBottomRightRadius: 30,
              borderBottomLeftRadius: 40,
            }}
          />
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="render square with rounded corners with different radii (start/end)">
        <View style={{width: '100%', height: 100, backgroundColor: 'gray'}}>
          <View
            style={{
              width: 100,
              height: 100,
              borderWidth: 3,
              borderColor: 'white',
              borderTopStartRadius: 10,
              borderTopEndRadius: 20,
              borderBottomEndRadius: 30,
              borderBottomStartRadius: 40,
            }}
          />
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="render squares with borderTopStartRadius and borderTopEndRadius">
        <View style={styles.squaresContainer}>
          <View style={[styles.square, {borderTopStartRadius: 24}]}>
            <Text style={styles.squareContent}>borderTopStartRadius</Text>
          </View>
          <View style={[styles.square, {borderTopEndRadius: 24}]}>
            <Text style={styles.squareContent}>borderTopEndRadius</Text>
          </View>
          <View
            style={[
              styles.square,
              {borderTopEndRadius: 24, borderTopStartRadius: 20},
            ]}>
            <Text style={styles.squareContent}>
              borderTopEndRadius + borderTopStartRadius
            </Text>
          </View>
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="render squares with borderBottomStartRadius + borderBottomEndRadius">
        <View style={styles.squaresContainer}>
          <View style={[styles.square, {borderBottomStartRadius: 24}]}>
            <Text style={styles.squareContent}>borderBottomStartRadius</Text>
          </View>
          <View style={[styles.square, {borderBottomEndRadius: 24}]}>
            <Text style={styles.squareContent}>borderBottomEndRadius</Text>
          </View>
          <View
            style={[
              styles.square,
              {borderBottomEndRadius: 24, borderBottomStartRadius: 24},
            ]}>
            <Text style={styles.squareContent}>
              borderBottomStartRadius + borderBottomEndRadius
            </Text>
          </View>
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="render circles">
        <View style={styles.squaresContainer}>
          <View style={[styles.square, {borderRadius: 50}]} />
          <View
            style={[
              styles.square,
              {
                borderBottomStartRadius: 50,
                borderBottomEndRadius: 50,
                borderTopStartRadius: 50,
                borderTopEndRadius: 50,
              },
            ]}
          />
          <View
            style={[
              styles.square,
              {
                borderBottomLeftRadius: 50,
                borderBottomRightRadius: 50,
                borderTopLeftRadius: 50,
                borderTopRightRadius: 50,
              },
            ]}
          />
        </View>
      </TestCase.Example>
      <TestCase.Example
        skip={{android: false, harmony: "Elliptical corners aren't supported"}}
        itShould="render a rectangle with corners rounded elliptically ">
        <View style={styles.squaresContainer}>
          <View
            style={[
              styles.square,
              {
                borderTopStartRadius: '25%',
                borderTopEndRadius: '50%',
                borderBottomEndRadius: '75%',
                borderBottomStartRadius: '100%',
                width: 300,
              },
            ]}
          />
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="render square with borders with different widths">
        <View style={{width: '100%', height: 100, backgroundColor: 'gray'}}>
          <View
            style={{
              width: 100,
              height: 100,
              borderColor: 'white',
              borderLeftWidth: 2,
              borderTopWidth: 4,
              borderRightWidth: 6,
              borderBottomWidth: 8,
            }}
          />
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="render rectangle with borders with different widths and colors">
        <View style={{width: '100%', height: 100, backgroundColor: 'gray'}}>
          <View
            style={{
              height: 80,
              width: 200,
              borderLeftWidth: 1,
              borderTopWidth: 10,
              borderRightWidth: 5,
              borderBottomWidth: 20,
              borderLeftColor: '#ff0000',
              borderRightColor: '#ffff00',
              borderTopColor: 'pink',
              borderBottomColor: 'skyblue',
            }}
          />
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="render square with borders with different colors">
        <View style={{width: '100%', height: 100, backgroundColor: 'gray'}}>
          <View
            style={{
              width: 100,
              height: 100,
              borderWidth: 3,
              borderLeftColor: 'blue',
              borderTopColor: 'red',
              borderRightColor: 'green',
              borderBottomColor: 'yellow',
            }}
          />
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="render square with borders with different start/end colors">
        <View style={{width: '100%', height: 100, backgroundColor: 'gray'}}>
          <View
            style={{
              width: 100,
              height: 100,
              borderWidth: 3,
              borderStartColor: 'blue',
              borderEndColor: 'green',
            }}
          />
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="render squares with borders with different style">
        <View
          style={{
            width: '100%',
            height: 100,
            backgroundColor: 'gray',
            flexDirection: 'row',
          }}>
          <View
            style={{
              width: 100,
              height: 100,
              marginEnd: 4,
              borderWidth: 3,
              borderColor: 'white',
              borderStyle: 'solid',
            }}
          />
          <View
            style={{
              width: 100,
              height: 100,
              marginEnd: 4,
              borderWidth: 3,
              borderColor: 'white',
              borderStyle: 'dotted',
            }}
          />
          <View
            style={{
              width: 100,
              height: 100,
              borderWidth: 3,
              borderColor: 'white',
              borderStyle: 'dashed',
            }}
          />
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="hide the overflow">
        <View
          style={{
            width: 64,
            height: 64,
            backgroundColor: 'red',
            overflow: 'hidden',
          }}
          collapsable={false}>
          <View
            style={{
              width: 64,
              height: 64,
              backgroundColor: 'green',
              marginLeft: 32,
            }}
          />
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="not hide the overflow">
        <View
          style={{
            width: 64,
            height: 64,
            backgroundColor: 'red',
          }}
          collapsable={false}>
          <View
            style={{
              width: 64,
              height: 64,
              backgroundColor: 'green',
              marginLeft: 32,
            }}
          />
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="not show view with height 0 and overflow hidden">
        <View
          style={{
            width: 64,
            height: 0,
            backgroundColor: 'red',
            overflow: 'hidden',
            margin: 10,
          }}>
          <View
            style={{
              width: 64,
              height: 64,
              backgroundColor: 'green',
              marginLeft: 32,
            }}
          />
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="render blue rectangle (zIndex test)">
        <View>
          <View
            style={{
              width: 64,
              height: 64,
              backgroundColor: 'blue',
              zIndex: 2,
              position: 'relative', // https://github.com/facebook/react-native/issues/38513
            }}
          />
          <View
            style={{
              width: 64,
              height: 64,
              backgroundColor: 'red',
              zIndex: 1,
              position: 'absolute',
            }}
          />
        </View>
      </TestCase.Example>
      <TestCase.Example
        itShould="render square with elevation"
        skip={{android: false, harmony: {arkTs: true, cAPI: true}}}
        //https://gl.swmansion.com/rnoh/react-native-harmony/-/issues/238
      >
        <View style={{width: '100%', height: 100}}>
          <View
            style={{
              width: 80,
              height: 80,
              margin: 10,
              backgroundColor: 'blue',
              elevation: 10,
            }}
          />
        </View>
      </TestCase.Example>
      <TestCase.Example
        skip={{
          android: false,
          harmony: {
            arkTs: true,
            cAPI: true,
          },
        }}
        itShould="show inner rectangle with the same color as the reference (needsOffscreenAlphaCompositing)"
        //https://gl.swmansion.com/rnoh/react-native-harmony/-/issues/322
      >
        <View
          style={{
            opacity: 0.5,
            backgroundColor: 'red',
            height: 100,
            width: 100,
          }}
          needsOffscreenAlphaCompositing>
          <View
            style={{
              backgroundColor: 'black',
              width: 60,
              height: 40,
              opacity: 0.5,
            }}
          />
        </View>
        <Text style={{height: 20}}>
          Reference black color with opacity: 0.5
        </Text>
        <View
          style={{
            width: 60,
            height: 40,
            backgroundColor: 'black',
            opacity: 0.5,
          }}
        />
      </TestCase.Example>
      <TestCase.Example itShould="show view with X moved by 500px right, Y scaled 2 times, rotated by 5deg">
        <View style={{width: '100%', height: 20}}>
          <View
            style={{
              width: 100,
              backgroundColor: 'blue',
              transform: [{translateX: 500}, {rotate: '5deg'}, {scaleY: 2}],
            }}>
            <Text style={{height: 20}}>Text</Text>
          </View>
        </View>
      </TestCase.Example>
      <TestSuite name="Hover">
        <TestCase.Manual
          initialState={{onPointerEnter: false}}
          arrange={({setState, reset}) => {
            return (
              <>
                <Button onPress={() => reset()} label="Reset" />
                <View
                  onPointerEnter={() => setState({onPointerEnter: true})}
                  style={{height: 100, width: 100, backgroundColor: 'red'}}
                />
              </>
            );
          }}
          assert={({expect, state}) => {
            expect(state).to.be.deep.eq({
              onPointerEnter: true,
            });
          }}
          itShould="Trigger onPointerEnter when the mouse pointer is moved over the component"
        />
        <TestCase.Manual
          initialState={{onPointerLeave: false}}
          arrange={({setState, reset}) => {
            return (
              <>
                <Button onPress={() => reset()} label="Reset" />
                <View
                  onPointerLeave={() => setState({onPointerLeave: true})}
                  style={{height: 100, width: 100, backgroundColor: 'red'}}
                />
              </>
            );
          }}
          assert={({expect, state}) => {
            expect(state).to.be.deep.eq({
              onPointerLeave: true,
            });
          }}
          itShould="Trigger onPointerLeave when the mouse pointer is moved away from the component."
        />
      </TestSuite>
      <TestSuite name="transform">
        <ToggleStyleTest
          propName="transform"
          propInitialValue={[]}
          propNewValue={[{translateX: 100}, {translateY: 10}]}
          style={{backgroundColor: 'yellow'}}
        />
        <ToggleStyleTest
          propName="transform"
          propInitialValue={[]}
          propNewValue={[{scaleX: 0.5}, {scaleY: 0.8}]}
          style={{backgroundColor: 'yellow'}}
        />
        <ToggleStyleTest
          propName="transform"
          propInitialValue={[]}
          propNewValue={[{rotateX: '45deg'}]}
          style={{backgroundColor: 'yellow'}}
        />
        <ToggleStyleTest
          propName="transform"
          propInitialValue={[]}
          propNewValue={[{rotateY: '45deg'}]}
          style={{backgroundColor: 'yellow'}}
        />
        <ToggleStyleTest
          propName="transform"
          propInitialValue={[]}
          propNewValue={[{rotateZ: '45deg'}]}
          style={{backgroundColor: 'yellow'}}
        />
        <ToggleStyleTest
          propName="transform"
          propInitialValue={[]}
          propNewValue={[{skewX: '45deg'}]}
          style={{backgroundColor: 'yellow'}}
        />
        <ToggleStyleTest
          propName="transform"
          propInitialValue={[]}
          propNewValue={[{skewY: '45deg'}]}
          style={{backgroundColor: 'yellow'}}
        />
        <ToggleStyleTest
          propName="transform"
          propInitialValue={[]}
          propNewValue={[{skewX: '30deg'}, {skewY: '30deg'}]}
          style={{backgroundColor: 'yellow'}}
        />
      </TestSuite>
      <TestSuite name="pointerEvents">
        <TestCase.Automated
          tags={['sequential']}
          itShould="call inner and outer view when pressing inner"
          initialState={{
            innerRef: createRef<View>(),
            outerRef: createRef<View>(),
            inner: false,
            outer: false,
            outerContainer: false,
          }}
          arrange={({setState, reset, state, done}) => {
            return (
              <PointerEventsView
                pointerEventsOuter="auto"
                setState={setState}
                reset={reset}
                innerRef={state.innerRef}
                done={done}
              />
            );
          }}
          act={async ({state}) => {
            await driver?.click({ref: state.innerRef});
          }}
          assert={({expect, state}) => {
            expect(state.inner).to.be.true;
            expect(state.outer).to.be.true;
            expect(state.outerContainer).to.be.true;
          }}
        />
        <TestCase.Automated
          tags={['sequential']}
          itShould="call only outer when pressing inner view"
          initialState={{
            inner: false,
            outer: false,
            outerContainer: true,
            innerRef: createRef<View>(),
            outerRef: createRef<View>(),
          }}
          arrange={({setState, reset, state, done}) => {
            return (
              <PointerEventsView
                pointerEventsOuter="box-only"
                setState={setState}
                reset={reset}
                innerRef={state.innerRef}
                done={done}
              />
            );
          }}
          act={async ({state}) => {
            await driver?.click({ref: state.innerRef});
          }}
          assert={({expect, state}) => {
            expect(state.inner).to.be.false;
            expect(state.outer).to.be.true;
            expect(state.outerContainer).to.be.true;
          }}
        />
        <TestCase.Automated
          tags={['sequential']}
          itShould="call inner and outer only when pressing inner view"
          initialState={{
            inner: false,
            outer: false,
            outerContainer: false,
            innerRef: createRef<View>(),
            outerRef: createRef<View>(),
          }}
          arrange={({setState, reset, state, done}) => {
            return (
              <PointerEventsView
                disableOuterContainerTouch
                pointerEventsOuter="box-none"
                setState={setState}
                reset={reset}
                innerRef={state.innerRef}
                done={done}
              />
            );
          }}
          act={async ({state}) => {
            await driver?.click({ref: state.innerRef});
          }}
          assert={({expect, state}) => {
            expect(state.inner).to.be.true;
            expect(state.outer).to.be.true;
          }}
        />
        <TestCase.Automated
          tags={['sequential']}
          itShould="not call inner or outer when pressing inner view"
          initialState={{
            inner: false,
            outer: false,
            outerContainer: false,
            innerRef: createRef<View>(),
            outerRef: createRef<View>(),
          }}
          arrange={({setState, reset, state, done}) => {
            return (
              <PointerEventsView
                pointerEventsOuter="none"
                setState={setState}
                reset={reset}
                innerRef={state.innerRef}
                done={done}
              />
            );
          }}
          act={async ({state}) => {
            await driver?.click({ref: state.innerRef});
          }}
          assert={({expect, state}) => {
            expect(state.inner).to.be.false;
            expect(state.outer).to.be.false;
            expect(state.outerContainer).to.be.true;
          }}
        />
        <TestCase.Automated
          tags={['sequential']}
          itShould="not call inner or outer when pressing outer views"
          initialState={{
            inner: false,
            outer: false,
            outerContainer: false,
            innerRef: createRef<View>(),
            outerRef: createRef<View>(),
          }}
          arrange={({setState, reset, state, done}) => {
            return (
              <PointerEventsView
                pointerEventsOuter="none"
                setState={setState}
                reset={reset}
                outerRef={state.outerRef}
                done={done}
              />
            );
          }}
          act={async ({state}) => {
            await driver?.click({ref: state.outerRef});
          }}
          assert={({expect, state}) => {
            expect(state.inner).to.be.false;
            expect(state.outer).to.be.false;
            expect(state.outerContainer).to.be.true;
          }}
        />
      </TestSuite>
      <TestCase.Automated
        tags={['sequential']}
        itShould="pass on touching blue background"
        initialState={{
          blueTouched: false,
          outerRef: createRef<View>(),
        }}
        arrange={({setState, state, done}) => (
          <View
            ref={state.outerRef}
            style={{
              backgroundColor: 'blue',
              alignSelf: 'center',
            }}>
            <View
              hitSlop={{top: 48, left: 48, bottom: 48, right: 48}}
              style={{
                width: 48,
                height: 48,
                backgroundColor: 'green',
                marginTop: 48,
                marginRight: 8,
                marginBottom: 48,
                marginLeft: 88,
              }}
              onTouchEnd={() => {
                setState(prevState => ({
                  ...prevState,
                  blueTouched: true,
                }));
                done();
              }}>
              <View
                style={{width: 48, height: 48, backgroundColor: 'red'}}
                onTouchEnd={e => {
                  e.stopPropagation();
                  done();
                }}
              />
            </View>
          </View>
        )}
        act={async ({state}) => {
          await driver?.click({ref: state.outerRef});
        }}
        assert={({expect, state}) => {
          expect(state.blueTouched).to.be.true;
        }}
      />
      <TestCase.Automated
        tags={['sequential']}
        itShould="pass on touching transparent view"
        initialState={{
          touched: false,
          ref: createRef<View>(),
        }}
        arrange={({setState, reset, state, done}) => (
          <>
            <View
              ref={state.ref}
              style={{
                backgroundColor: 'transparent',
                width: '100%',
                height: 100,
              }}
              onTouchEnd={() => {
                setState(prevState => ({
                  ...prevState,
                  touched: true,
                }));
                done();
              }}
            />
            <Button label="reset" onPress={reset} />
          </>
        )}
        act={async ({state}) => {
          await driver?.click({ref: state.ref});
        }}
        assert={({expect, state}) => {
          expect(state.touched).to.be.true;
        }}
      />

      <TestCase.Manual
        itShould="blue view should not allow clicks with non-touch input device"
        modal
        initialState={{first: false, second: false, third: false}}
        arrange={({setState}) => (
          <View style={{width: '100%', height: 100, flexDirection: 'row'}}>
            <TouchableWithoutFeedback
              onPress={() => setState(prev => ({...prev, first: true}))}>
              <View
                style={{
                  width: 76,
                  height: 76,
                  marginRight: 4,
                  backgroundColor: 'red',
                }}
              />
            </TouchableWithoutFeedback>
            <TouchableWithoutFeedback
              onPress={() => setState(prev => ({...prev, second: true}))}>
              <View
                style={{
                  width: 76,
                  height: 76,
                  marginRight: 4,
                  backgroundColor: 'blue',
                }}
                // @ts-ignore
                tabIndex={-1}
              />
            </TouchableWithoutFeedback>
            <TouchableWithoutFeedback
              onPress={() => setState(prev => ({...prev, third: true}))}>
              <View
                style={{
                  width: 76,
                  height: 76,
                  marginRight: 4,
                  backgroundColor: 'red',
                }}
              />
            </TouchableWithoutFeedback>
          </View>
        )}
        assert={({state, expect}) => {
          expect(state).to.be.deep.eq({
            first: true,
            second: false,
            third: true,
          });
        }}
      />
      <TestCase.Example itShould="render view with fixed width and aspectRatio 1">
        <View style={{width: '100%', height: 100}}>
          <View
            style={{
              width: 100,
              backgroundColor: 'blue',
              aspectRatio: 1,
            }}
          />
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="render views with set flex and aspectRatio 1">
        <View style={{width: '100%', height: 100}}>
          <View
            style={{
              width: 100,
              backgroundColor: 'blue',
              flex: 1,
              aspectRatio: 1,
            }}
          />
          <View
            style={{
              width: 100,
              backgroundColor: 'blue',
              flex: 2,
              aspectRatio: 1,
            }}
          />
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="show view rotated by 180deg(backfaceVisibility: visible)">
        <View style={{width: '100%', height: 20}}>
          <View
            style={{
              width: 100,
              backgroundColor: 'blue',
              transform: [{rotateY: '180deg'}],
              backfaceVisibility: 'visible',
            }}>
            <Text style={{height: 20}}>Backface</Text>
          </View>
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="not show view rotated by 180deg(backfaceVisibility: hidden)">
        <View style={{width: '100%', height: 20}}>
          <View
            style={{
              width: 100,
              backgroundColor: 'blue',
              transform: [{rotateY: '180deg'}],
              backfaceVisibility: 'hidden',
            }}>
            <Text style={{height: 20}}>Backface</Text>
          </View>
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="render light blue shadow shifted towards bottom and right">
        <View
          style={{
            width: 64,
            height: 64,
            margin: 8,
            backgroundColor: 'green',
            shadowColor: 'blue',
            shadowOffset: {width: 16, height: 16},
            shadowOpacity: 0.25,
            shadowRadius: 16,
          }}
        />
      </TestCase.Example>
      <TestCase.Example itShould="View Overflow type hidden test by exceeded text">
        <View
          style={{
            backgroundColor: 'rgba(0,255,0,1)',
            width: 150,
            height: 100,
            overflow: 'hidden',
          }}
          collapsable={false}>
          <Text>
            Michaelmas term lately over, and the Lord Chancellor sitting in
            Lincoln's Inn Hall. Implacable November weather. As much mud in the
            streets as if the waters had but newly retired from the face of the
            earth.
          </Text>
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="View Overflow type visible test by exceeded text">
        <View
          style={{
            backgroundColor: 'rgba(0,255,0,1)',
            width: 150,
            height: 100,
            overflow: 'visible',
          }}
          collapsable={false}>
          <Text>
            Michaelmas term lately over, and the Lord Chancellor sitting in
            Lincoln's Inn Hall. Implacable November weather. As much mud in the
            streets as if the waters had but newly retired from the face of the
            earth.
          </Text>
        </View>
      </TestCase.Example>
      <TestCase.Example
        itShould="render a view with role"
        skip={{android: false, harmony: {arkTs: true, cAPI: true}}} // https://gl.swmansion.com/rnoh/react-native-harmony/-/issues/603
      >
        <View role="alert">
          <Text>Alert</Text>
        </View>
      </TestCase.Example>
      <TestCase.Automated
        tags={['sequential']}
        itShould="pass when pointer starts moving over blue rect (onResponderReject)"
        skip="Not implemented properly"
        initialState={{
          responderRejectedCount: 0,
          responderGrantedCount: 0,
          childResponderGrantedCount: 0,
          ref: createRef<View>(),
        }}
        arrange={({setState, state, done}) => {
          return (
            <View
              onMoveShouldSetResponder={() => true}
              onResponderReject={() => {
                setState(prev => ({
                  ...prev,
                  responderRejectedCount: prev.responderRejectedCount + 1,
                }));
                done();
              }}
              onResponderGrant={() => {
                setState(prev => ({
                  ...prev,
                  responderGrantedCount: prev.responderGrantedCount + 1,
                }));
                done();
              }}
              style={{
                backgroundColor: 'green',
                padding: 20,
              }}>
              <View
                ref={state.ref}
                style={{backgroundColor: 'blue', width: 64, height: 64}}
                onResponderTerminationRequest={() => false}
                onStartShouldSetResponder={() => true}
                onResponderGrant={() => {
                  setState(prev => ({
                    ...prev,
                    childResponderGrantedCount:
                      prev.childResponderGrantedCount + 1,
                  }));
                }}
              />
            </View>
          );
        }}
        act={async () => {
          // TODO: Fix this test. It was improperly adapted. Driver needs to support move command.
          // https://gl.swmansion.com/rnoh/react-native-harmony-test-kit/-/issues/3
          // driver?.move({
          //   from: {ref: state.ref, offset: {fromTopLeft: {x: 8, y: 8}}},
          //   to: {ref: state.ref, offset: {fromTopRight: {x: 8, y: 8}}},
          // });
        }}
        assert={({expect, state}) => {
          expect(state.responderRejectedCount).to.be.greaterThan(0);
        }}
      />
      <ViewAccessibilityTest />
      <TestCase.Manual
        modal
        itShould='call the "escape" gesture handler'
        initialState={false}
        skip={{android: false, harmony: {arkTs: true, cAPI: true}}} // https://gl.swmansion.com/rnoh/react-native-harmony/-/issues/602
        arrange={({setState}) => (
          <View
            accessible={true}
            style={{width: '100%', height: 100, backgroundColor: 'gray'}}
            onAccessibilityEscape={() => {
              console.log('onAccessibilityEscape called!');
              setState(true);
            }}>
            <View
              style={{
                width: 100,
                height: 100,
                backgroundColor: 'red',
              }}
            />
          </View>
        )}
        assert={({expect, state}) => {
          expect(state).to.be.true;
        }}
      />
      <TestCase.Example
        modal
        itShould='render "First Layout" view and ignore "Ignored Layout" when accessibility is true'>
        <View accessible={true} style={styles.accessibilityContainer}>
          <View
            style={[styles.accessibilityLayout, {backgroundColor: 'green'}]}
            importantForAccessibility="yes">
            <Text>First layout</Text>
          </View>
          <View
            style={[styles.accessibilityLayout, {backgroundColor: 'yellow'}]}
            importantForAccessibility="no-hide-descendants">
            <Text>Ignored Layout</Text>
          </View>
        </View>
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="make the screen reader say/display 'busy' after clicking on the background">
        <View
          accessible={true}
          aria-busy={true}
          style={styles.accessibilityLayout}
        />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="make the screen reader say/display: 'checked, mixed' when both button are 'checked', 'mixed' when one of the button is 'checked' and 'unchecked' when none of the button is 'checked'">
        <ViewAccessibilityAriaChecked />
      </TestCase.Example>
      <TestCase.Example
        modal
        skip="only works on iOS"
        itShould="make the screen reader hide 'Hidden layout' accessibilityHidden">
        <View accessible={true} style={styles.accessibilityContainer}>
          <View
            style={[styles.accessibilityLayout, {backgroundColor: 'green'}]}>
            <Text>First layout</Text>
          </View>
          <View
            style={[styles.accessibilityLayout, {backgroundColor: 'yellow'}]}
            accessibilityElementsHidden={true}>
            <Text>Hidden Layout</Text>
          </View>
        </View>
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="make the screen reader say/display 'This view has a red background' and 'Hint: and no text'">
        <View
          accessible={true}
          aria-label="This view has a red background"
          accessibilityHint="Hint: and no text"
          style={[styles.accessibilityLayout, {backgroundColor: 'red'}]}
        />
      </TestCase.Example>
      <TestCase.Example
        skip={{android: false, harmony: {arkTs: true, cAPI: true}}}
        modal
        itShould="allow user to move with keyboard's arrows keys between blue squares">
        <ViewNextFocus />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="Change the various properties of the View by using setNativeProps">
        <SetNativePropsTest />
      </TestCase.Example>
    </TestSuite>
  );
}

function PointerEventsView(props: {
  disableOuterContainerTouch?: boolean;
  pointerEventsOuter?: 'box-none' | 'none' | 'box-only' | 'auto';
  pointerEventsInner?: 'box-none' | 'none' | 'box-only' | 'auto';
  outerRef?: React.RefObject<View | null>;
  innerRef?: React.RefObject<View | null>;
  done: () => void;
  setState: React.Dispatch<
    React.SetStateAction<{
      innerRef: React.RefObject<View | null>;
      outerRef: React.RefObject<View | null>;
      inner: boolean;
      outer: boolean;
      outerContainer: boolean;
    }>
  >;
  reset: () => void;
}) {
  return (
    <View style={{height: 100, width: '100%', flexDirection: 'row'}}>
      <View
        style={{backgroundColor: 'green'}}
        onTouchEnd={
          props.disableOuterContainerTouch
            ? undefined
            : () => {
                props.setState(prev => ({...prev, outerContainer: true}));
                props.done();
              }
        }>
        <View
          ref={props.outerRef}
          style={{
            height: 100,
            width: 100,
            backgroundColor: 'red',
            alignItems: 'flex-end',
            justifyContent: 'center',
          }}
          pointerEvents={props.pointerEventsOuter}
          onTouchEnd={() => {
            props.setState(prev => ({...prev, outer: true}));
            props.done();
          }}>
          <View
            ref={props.innerRef}
            style={{
              height: 40,
              width: 40,
              backgroundColor: 'blue',
              marginRight: 5,
            }}
            onTouchEnd={() => {
              props.setState(prev => ({...prev, inner: true}));
              props.done();
            }}
            pointerEvents={props.pointerEventsInner}
          />
        </View>
      </View>
      <Button label="reset" onPress={props.reset} />
    </View>
  );
}

function ViewAccessibilityAriaChecked() {
  const [firstChecked, setFirstChecked] = useState<boolean>(false);
  const [secondChecked, setSecondChecked] = useState<boolean>(false);

  const checked = firstChecked && secondChecked;
  const mixed = firstChecked !== secondChecked;

  return (
    <View
      accessible={true}
      aria-checked={checked ? true : mixed ? 'mixed' : false}
      style={[styles.accessibilityLayout, {height: 200}]}
      accessibilityRole="checkbox"
      accessibilityState={{checked}}>
      <Button
        label={`First Element is ${firstChecked ? 'checked' : 'unchecked'}`}
        onPress={() => setFirstChecked(!firstChecked)}
      />
      <Button
        label={`Second Element is ${secondChecked ? 'checked' : 'unchecked'}`}
        onPress={() => setSecondChecked(!secondChecked)}
      />
    </View>
  );
}

const BasicView = React.forwardRef<View, any>(({text, ...props}, ref) => (
  <View ref={ref} style={styles.gridContainerSquare} focusable {...props}>
    <Text style={styles.squareContent}>{text}</Text>
  </View>
));

function ViewNextFocus() {
  const [pressCounter, setPressCounter] = useState(0);

  const topLeftViewRef = React.useRef<View>(null);
  const topRightViewRef = React.useRef<View>(null);
  const midLeftViewRef = React.useRef<View>(null);
  const midRightViewRef = React.useRef<View>(null);
  const botLeftViewRef = React.useRef<View>(null);
  const botRightViewRef = React.useRef<View>(null);

  // Implementation details:
  // normally, in order to detect change in ref we would use callback ref
  // https://legacy.reactjs.org/docs/refs-and-the-dom.html#callback-refs
  // to make it very simply, we use button to force rerender of the component
  // to get the "updated" ref
  const topLeftViewNode = findNodeHandle(topLeftViewRef.current);
  const topRightViewNode = findNodeHandle(topRightViewRef.current);
  const midLeftViewNode = findNodeHandle(midLeftViewRef.current);
  const midRightViewNode = findNodeHandle(midRightViewRef.current);
  const botLeftViewNode = findNodeHandle(botLeftViewRef.current);
  const botRightViewNode = findNodeHandle(botRightViewRef.current);

  return (
    <View style={{height: '90%'}}>
      <Button
        label={`Rerender (${pressCounter}) Component - force ref to be updated`}
        onPress={() => setPressCounter(count => count + 1)}
      />
      <View style={styles.gridContainer}>
        <BasicView
          ref={topLeftViewRef}
          text="Top Left"
          nextFocusUp={botLeftViewNode ?? undefined}
          nextFocusLeft={botRightViewNode ?? undefined}
        />
        <BasicView
          ref={topRightViewRef}
          text="Top Right"
          nextFocusUp={botRightViewNode ?? undefined}
          nextFocusRight={midLeftViewNode ?? undefined}
        />
        <BasicView
          ref={midLeftViewRef}
          text="Mid Left"
          nextFocusLeft={topRightViewNode ?? undefined}
        />
        <BasicView
          ref={midRightViewRef}
          text="Mid Right"
          nextFocusRight={botLeftViewNode ?? undefined}
        />
        <BasicView
          ref={botLeftViewRef}
          text="Bot Left"
          nextFocusDown={topLeftViewNode ?? undefined}
          nextFocusLeft={midRightViewNode ?? undefined}
        />
        <BasicView
          ref={botRightViewRef}
          text="Bot Right"
          nextFocusDown={topRightViewNode ?? undefined}
          nextFocusRight={topLeftViewNode ?? undefined}
        />
      </View>
    </View>
  );
}

function SetNativePropsTest() {
  return (
    <>
      <SetNativePropsTestProp
        propName="height"
        propInitialValue={50}
        propNewValue={100}
      />
      <SetNativePropsTestProp
        propName="backgroundColor"
        propInitialValue="red"
        propNewValue="blue"
      />
      <SetNativePropsTestProp
        propName="borderWidth"
        propInitialValue={10}
        propNewValue={1}
      />
      <SetNativePropsTestProp
        propName="borderColor"
        propInitialValue="red"
        propNewValue="blue"
        style={{borderWidth: 20}}
      />
      <SetNativePropsTestProp
        propName="borderStyle"
        propInitialValue="dotted"
        propNewValue="dashed"
        style={{borderWidth: 20}}
      />
      <SetNativePropsTestProp
        propName="opacity"
        propInitialValue={1}
        propNewValue={0.3}
        style={{backgroundColor: 'blue'}}
      />
      <SetNativePropsTestProp
        propName="backfaceVisibility"
        propInitialValue="visible"
        propNewValue="hidden"
        style={{backgroundColor: 'blue', transform: [{rotateY: '180deg'}]}}
      />
      <SetNativePropsTestProp
        propName="transform"
        propInitialValue={[{rotateY: '45deg'}]}
        propNewValue={[{rotateY: '0deg'}]}
        style={{backgroundColor: 'blue'}}
      />
      <SetNativePropsTestZIndexProp
        propName="zIndex"
        propInitialValue={3}
        propNewValue={1}
      />
      <SetNativePropsTestProp
        propName="shadowColor"
        propInitialValue="#ff00ff"
        propNewValue="#ffff00"
        style={{
          margin: 20,
          backgroundColor: 'blue',
          shadowOffset: {width: 20, height: 20},
          shadowOpacity: 0.8,
          shadowRadius: 3,
        }}
      />
    </>
  );
}

function SetNativePropsTestProp({
  propName,
  propInitialValue,
  propNewValue,
  style,
}: any) {
  const viewRef = useRef<View>(null);
  const onPress = () => {
    viewRef?.current?.setNativeProps({[propName]: propNewValue});
  };
  return (
    <TouchableWithoutFeedback onPress={onPress}>
      <View
        ref={viewRef}
        style={{...style, minHeight: 50, [propName]: propInitialValue}}>
        <Text>Press Me to change the {propName} value of the View</Text>
      </View>
    </TouchableWithoutFeedback>
  );
}

function ToggleStyleTest({
  propName,
  propInitialValue,
  propNewValue,
  style,
}: any) {
  const [propValue, setPropValue] = useState(propInitialValue);
  const viewRef = useRef<View>(null);
  const onPress = () => {
    setPropValue(
      propValue === propInitialValue ? propNewValue : propInitialValue,
    );
  };
  return (
    <TestCase.Example
      itShould={`set ${propName} to ${JSON.stringify(propValue)}`}>
      <TouchableWithoutFeedback onPress={onPress}>
        <View
          ref={viewRef}
          style={{
            ...style,
            width: '30%',
            minHeight: 50,
            [propName]: propValue,
            alignSelf: 'center',
            alignContent: 'center',
          }}>
          <Text>Click me</Text>
        </View>
      </TouchableWithoutFeedback>
    </TestCase.Example>
  );
}

function SetNativePropsTestZIndexProp(props: any) {
  return (
    <>
      <View>
        <View
          style={{
            minHeight: 50,
            backgroundColor: 'red',
            zIndex: 2,
            position: 'relative',
          }}
        />
        <SetNativePropsTestProp
          {...props}
          style={{backgroundColor: 'blue', position: 'absolute'}}
        />
      </View>
    </>
  );
}

const styles = StyleSheet.create({
  squaresContainer: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    backgroundColor: 'gray',
  },
  square: {
    width: 100,
    height: 100,
    backgroundColor: 'lightblue',
    margin: 4,
  },
  squareContent: {
    textAlignVertical: 'center',
    textAlign: 'center',
    height: '100%',
  },
  accessibilityContainer: {
    width: '100%',
    backgroundColor: 'gray',
  },
  accessibilityLayout: {
    width: '100%',
    height: 100,
    backgroundColor: 'lightblue',
  },
  gridContainer: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    justifyContent: 'center',
    alignItems: 'center',
    gap: 10,
  },
  gridContainerSquare: {
    width: 150,
    height: 150,
    backgroundColor: 'lightblue',
    margin: 4,
  },
});