/**

 * 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 { useEffect, useRef, useState } from 'react';

import {

  Animated,

  PanResponder,

  ScrollView,

  Text,

  TextInput,

  TouchableOpacity,

  View,

  ViewStyle,

} from 'react-native';

import { Button } from '../components';

import React from 'react';



export function TouchHandlingTest() {

  return (

    <TestSuite name="Touch Handling">

      <TestCase

        itShould="pass when pressed red rectangle"

        initialState={false}

        arrange={({ setState }) => {

          return (

            <TouchIssue1

              onPress={() => {

                setState(true);

              }}

            />

          );

        }}

        assert={({ expect, state }) => {

          expect(state).to.be.true;

        }}

      />



      <TestCase

        itShould="register a touch after native transform animation"

        initialState={false}

        arrange={({ setState }) => (

          <RectangleSlider

            onPress={() => {

              setState(prev => !prev);

            }}

          />

        )}

        assert={({ expect, state }) => {

          expect(state).to.be.true;

        }}

      />

      <TestCase

        itShould="handle press on rotated view"

        initialState={false}

        arrange={({ setState }) => (

          <TouchableTransformedTest

            setState={setState}

            transform={[{ rotate: '180deg' }, { translateX: 100 }]}

          />

        )}

        assert={({ expect, state }) => {

          expect(state).to.be.true;

        }}

      />

      <TestCase

        itShould="handle press on scaled view"

        initialState={false}

        arrange={({ setState }) => (

          <TouchableTransformedTest

            setState={setState}

            transform={[{ scaleX: -1 }, { translateX: 100 }]}

          />

        )}

        assert={({ expect, state }) => {

          expect(state).to.be.true;

        }}

      />

      <TestCase itShould="report transformed touch coordinates">

        <TouchCoordinatesTest

          transform={[

            { rotate: '45deg' },

            { translateY: 50 },

            { translateX: -50 },

            { scaleY: -1 },

            { scale: 0.75 },

          ]}

        />

      </TestCase>

      <TestCase itShould="report transformed touch coordinates">

        <TouchCoordinatesTest

          transform={[

            { rotate: '-45deg' },

            { translateY: 50 },

            { translateX: -50 },

            { scaleX: -1 },

            { scaleY: 1.25 },

          ]}

        />

      </TestCase>

      <TestCase

        itShould="respond to touches on disabled components when wrapped in Touchables"

        initialState={false}

        arrange={({ setState }) => (

          <TouchableOpacity

            onPress={() => {

              setState(true);

            }}>

            <TextInput

              editable={false}

              style={{

                borderWidth: 2,

                borderColor: 'blue',

              }}

              value={'Non-editable TextInput'}

            />

          </TouchableOpacity>

        )}

        assert={({ expect, state }) => {

          expect(state).to.be.true;

        }}

      />

      <TestCase

        modal

        itShould="allow vertical scroll when flinging fast after horizontal swipe on gray area">

        <ScrollViewLockedIssue />

      </TestCase>

    </TestSuite>

  );

}



function RectangleSlider(props: { onPress: () => void }) {

  const square1Anim = useRef(new Animated.Value(0)).current;

  const animation = Animated.timing(square1Anim, {

    toValue: 64,

    duration: 1000,

    useNativeDriver: true,

  });

  const handleAnimation = () => {

    animation.reset();

    animation.start();

  };



  return (

    <>

      <Animated.View

        onTouchEnd={() => {

          props.onPress();

        }}

        style={{

          height: 64,

          width: 64,

          backgroundColor: 'red',

          transform: [

            {

              translateX: square1Anim,

            },

          ],

        }}

      />

      <Button label="Animate" onPress={handleAnimation} />

    </>

  );

}



function TouchableTransformedTest({

  setState,

  transform,

}: {

  setState: (v: boolean) => void;

  transform: ViewStyle['transform'];

}) {

  return (

    <View

      style={{

        alignSelf: 'center',

        width: 75,

        backgroundColor: 'red',

        transform,

      }}>

      <TouchableOpacity onPress={() => setState(true)}>

        <Text>Press me!</Text>

      </TouchableOpacity>

    </View>

  );

}



function TouchCoordinatesTest({

  transform,

}: {

  transform?: ViewStyle['transform'];

}) {

  const [position, setPosition] = React.useState({ x: 0, y: 0 });



  return (

    <View style={{ height: 250 }}>

      <Text>Touch coordinates: {JSON.stringify(position)}</Text>

      <View

        style={{

          alignSelf: 'center',

          width: 150,

          height: 150,

          backgroundColor: 'red',

          transform,

          opacity: 0.5,

        }}

        onTouchStart={e => {

          setPosition({

            x: Math.round(e.nativeEvent.locationX),

            y: Math.round(e.nativeEvent.locationY),

          });

        }}

        onTouchMove={e => {

          setPosition({

            x: Math.round(e.nativeEvent.locationX),

            y: Math.round(e.nativeEvent.locationY),

          });

        }}>

        <Text>Top left</Text>

      </View>

    </View>

  );

}



const TouchIssue1 = ({ onPress }: { onPress: () => void }) => {

  const nPressesRef = useRef(0);

  const [nRenders, setNRenders] = useState(0);

  const [label, setLabel] = useState('hello');



  useEffect(() => {

    const timeout = setTimeout(() => {

      setNRenders(1);

    }, 2000);

    return () => {

      clearTimeout(timeout);

    };

  }, []);



  if (nRenders > 0) {

    return (

      <View style={{ opacity: 1, marginTop: 50 }}>

        <View collapsable={false}>

          <TouchableOpacity

            onPress={() => {

              onPress();

              setLabel(`${label}+${nPressesRef.current}`);

              nPressesRef.current++;

            }}>

            <Text>{label}</Text>

            <View

              id="foo"

              style={{ height: 100, width: 100, backgroundColor: 'red' }}

            />

          </TouchableOpacity>

        </View>

      </View>

    );

  } else {

    return (

      <View style={{ opacity: 0, marginTop: 50 }}>

        <View collapsable={false}>

          <View style={{ height: 100, width: 100 }} />

        </View>

      </View>

    );

  }

};



class ScrollViewLockedIssue extends React.Component {

  textInput: any;

  blur = () => {

    this.textInput.blur();

  };

  _gestureHandlers: any;

  componentWillMount() {

    this._gestureHandlers = PanResponder.create({

      onStartShouldSetPanResponder: () => true,

      onStartShouldSetPanResponderCapture: () => false,

      onMoveShouldSetPanResponder: (event, gestureState) => {

        const touchCapture =

          Math.abs(gestureState.dx) > 10 || Math.abs(gestureState.dy) > 10;

        return touchCapture;

      },

      onMoveShouldSetPanResponderCapture: () => false,

      onPanResponderMove: (_evt, _gestureState) => {

        console.warn('move');

      },

    });

  }



  render(): React.ReactNode {

    return (

      <ScrollView style={{ height: '75%' }}>

        <View style={{ height: 100 }}>

          <Text>this is first part</Text>

        </View>

        <View

          style={{ height: 300, backgroundColor: 'green' }}

          {...this._gestureHandlers.panHandlers}>

          <Text>this is second part</Text>

        </View>

        <View

          style={{

            height: 800,

            backgroundColor: 'yellow',

          }}

          {...this._gestureHandlers.panHandlers}>

          <TouchableOpacity>

            <Text style={{ backgroundColor: 'gray', height: 100 }}>

              SWIPE HORIZONTALLY HERE

            </Text>

          </TouchableOpacity>

        </View>

      </ScrollView>

    );

  }

}