/**

 * 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 { TestSuite, TestCase } from '@rnoh/testerino';

import {

  Keyboard,

  StyleSheet,

  TextInput,

  KeyboardEvent,

  Dimensions,

} from 'react-native';

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

import { useEffect } from 'react';

import { EmitterSubscription } from 'react-native/Libraries/vendor/emitter/EventEmitter';



export function KeyboardTest() {

  return (

    <TestSuite name="Keyboard">

      <TestCase

        itShould="not crash when using keyboard module"

        fn={({ expect }) => {

          expect(Keyboard.isVisible()).to.be.false;

        }}

      />

      <TestCase modal itShould="dismiss keyboard on button press">

        <TextInput style={styles.textInput} />

        <Button label="Dismiss keyboard" onPress={() => Keyboard.dismiss()} />

      </TestCase>

      <TestCase

        modal

        skip

        initialState={{

          keyboardDidHide: false,

          keyboardDidShow: true,

          keyboardEvent: {} as KeyboardEvent,

        }}

        itShould="not open the keyboard after opening the modal"

        arrange={({ setState, reset }) => {

          return (

            <KeyboardEventsView

              listenToShow

              checkIfKeyboardIsVisible

              onSetState={setState}

              reset={reset}

            />

          );

        }}

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

          expect(state.keyboardDidShow).to.be.false;

          expect(state.keyboardDidHide).to.be.false;

        }}

      // https://gl.swmansion.com/rnoh/react-native-harmony/-/issues/380

      />

      <TestCase

        modal

        initialState={{

          keyboardDidHide: false,

          keyboardDidShow: false,

          keyboardEvent: {} as KeyboardEvent,

        }}

        itShould="pass after opening the keyboard"

        arrange={({ setState, reset }) => {

          return (

            <KeyboardEventsView

              listenToShow

              dismissOnReset

              onSetState={setState}

              reset={reset}

            />

          );

        }}

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

          expect(state.keyboardDidShow).to.be.true;

          expect(state.keyboardDidHide).to.be.false;

          expect(state.keyboardEvent.endCoordinates.height).to.be.greaterThan(

            0,

          );

          expect(state.keyboardEvent.endCoordinates.width).to.be.greaterThan(0);

          expect(state.keyboardEvent.endCoordinates.screenY).to.be.lessThan(

            Dimensions.get('window').height,

          );

          expect(state.keyboardEvent.endCoordinates.screenX).to.be.equal(0);

        }}

      />

      <TestCase

        modal

        initialState={{

          keyboardDidHide: false,

          keyboardDidShow: false,

          keyboardEvent: {} as KeyboardEvent,

        }}

        itShould="pass after dismissing the keyboard"

        arrange={({ setState, reset }) => {

          return (

            <KeyboardEventsView

              listenToHide

              showDismissButton

              onSetState={setState}

              reset={reset}

            />

          );

        }}

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

          expect(state.keyboardDidHide).to.be.true;

          expect(state.keyboardDidShow).to.be.false;

          expect(state.keyboardEvent.endCoordinates.height).to.be.equal(0);

          expect(state.keyboardEvent.endCoordinates.width).to.be.greaterThan(0);

          expect(state.keyboardEvent.endCoordinates.screenY).to.be.closeTo(

            Dimensions.get('window').height,

            10,

          );

          expect(state.keyboardEvent.endCoordinates.screenX).to.be.equal(0);

        }}

      />

    </TestSuite>

  );

}



function KeyboardEventsView(props: {

  autofocus?: boolean;

  dismissOnReset?: boolean;

  listenToHide?: boolean;

  checkIfKeyboardIsVisible?: boolean;

  listenToShow?: boolean;

  showDismissButton?: boolean;

  onSetState: React.Dispatch<

    React.SetStateAction<{

      keyboardDidShow: boolean;

      keyboardDidHide: boolean;

      keyboardEvent: KeyboardEvent;

    }>

  >;

  reset: () => void;

}) {

  useEffect(() => {

    let showSubscription: EmitterSubscription;

    let hideSubscription: EmitterSubscription;

    if (props.listenToShow) {

      showSubscription = Keyboard.addListener('keyboardDidShow', event => {

        props.onSetState(prev => ({

          ...prev,

          keyboardEvent: event,

          keyboardDidShow: true,

        }));

      });

    }

    if (props.listenToHide) {

      hideSubscription = Keyboard.addListener('keyboardDidHide', event => {

        props.onSetState(prev => ({

          ...prev,

          keyboardEvent: event,

          keyboardDidHide: true,

        }));

      });

    }

    if (props.checkIfKeyboardIsVisible) {

      setTimeout(() => {

        if (!Keyboard.isVisible()) {

          props.onSetState(prev => ({ ...prev, keyboardDidShow: false }));

        }

      }, 1000);

    }



    return () => {

      if (props.listenToShow) {

        showSubscription.remove();

      }

      if (props.listenToHide) {

        hideSubscription.remove();

      }

    };

  }, []);



  return (

    <>

      <TextInput style={styles.textInput} autoFocus={props.autofocus} />

      {props.showDismissButton && (

        <Button label={'dismiss keyboard'} onPress={() => Keyboard.dismiss()} />

      )}

      <Button

        label="reset"

        onPress={() => {

          if (props.dismissOnReset) {

            Keyboard.dismiss();

          }

          props.reset();

        }}

      />

    </>

  );

}



const styles = StyleSheet.create({

  textInput: {

    borderWidth: 1,

    borderColor: 'silver',

    backgroundColor: '#444',

    height: 32, // hack

    borderRadius: 8,

    marginTop: 8,

    padding: 8,

    fontSize: 16,

    color: 'white',

  },

  buttonText: {

    width: '100%',

    height: '100%',

    fontWeight: 'bold',

  },

});



export default KeyboardTest;