/**

 * 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 {

  ReturnKeyType,

  ReturnKeyTypeAndroid,

  StyleSheet,

  Text,

  TextInput,

  TextInputProps,

  View,

} from 'react-native';

import { TestSuite, TestCase } from '@rnoh/testerino';

import { useState, useRef } from 'react';

import { Button, Effect, StateKeeper } from '../components';



export function TextInputTest() {

  return (

    <TestSuite name="TextInput">

      <TestCase

        modal

        itShould="render textinput and change the text component based on the values inputted">

        <TextInputWithText style={styles.textInput} />

      </TestCase>

      <TestCase modal itShould="render non-editable textInput">

        <TextInputWithText style={styles.textInput} editable={false} />

      </TestCase>

      <TestCase modal itShould="render textInput with Pacifico Regular font">

        <TextInputWithText

          style={[styles.textInput, { fontFamily: 'Pacifico-Regular' }]}

        />

      </TestCase>

      <TestCase modal itShould="render textInput with caret hidden">

        <TextInputWithText style={styles.textInput} caretHidden />

      </TestCase>

      <TestSuite name="focus/blur">

        <TestCase

          modal

          itShould="blur text on submit (singleline)"

          initialState={false}

          arrange={({ setState }) => {

            return (

              <>

                <TextInputWithText

                  style={styles.textInput}

                  blurOnSubmit

                  onBlur={() => setState(true)}

                />

              </>

            );

          }}

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

            expect(state).to.be.true;

          }}

        />

        <TestCase

          modal

          itShould="blur text after switching to another textinput"

          initialState={false}

          arrange={({ setState }) => {

            return (

              <>

                <TextInputWithText

                  style={styles.textInput}

                  onBlur={() => setState(true)}

                />

                <TextInputWithText

                  style={styles.textInput}

                  onBlur={() => setState(true)}

                />

              </>

            );

          }}

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

            expect(state).to.be.true;

          }}

        />

        <TestCase

          modal

          itShould="not blur text on submit"

          skip

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

        >

          <TextInputWithText style={styles.textInput} blurOnSubmit={false} />

          <TextInputWithText

            style={styles.textInput}

            blurOnSubmit={false}

            multiline

          />

        </TestCase>

        <TestCase

          modal

          itShould="automatically focus textInput when displayed"

          initialState={false}

          arrange={({ setState }) => (

            <TextInputWithText

              style={styles.textInput}

              autoFocus

              onFocus={() => setState(true)}

            />

          )}

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

            expect(state).to.be.true;

          }}

        />

        <TestCase

          modal

          itShould="focus textInput on click"

          initialState={false}

          arrange={({ setState }) => (

            <TextInput

              style={styles.textInput}

              onFocus={() => setState(true)}

            />

          )}

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

            expect(state).to.be.true;

          }}

        />

        <TestCase

          modal

          itShould="focus textInput when pressing the button"

          initialState={false}

          arrange={({ setState }) => <FocusTextInputTest setState={setState} />}

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

            expect(state).to.be.true;

          }}

        />

      </TestSuite>

      <TestCase

        modal

        itShould="render textInput with blue underline"

        skip

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

      >

        <TextInputWithText

          style={styles.textInput}

          underlineColorAndroid={'blue'}

        />

      </TestCase>

      <TestCase modal itShould="render textinput with red placeholder">

        <TextInputWithText

          style={styles.textInput}

          placeholder="Placeholder"

          placeholderTextColor={'red'}

        />

      </TestCase>

      <TestCase modal itShould="render textinput with green selection color">

        <TextInputWithText style={styles.textInput} selectionColor="green" />

      </TestCase>

      <TestCase modal itShould="render multiline text input">

        <TextInputWithText style={styles.textInputBigger} multiline />

      </TestCase>

      <TestCase

        modal

        itShould="render multiline text input with Pacifico Regular font">

        <TextInputWithText

          style={[styles.textInputBigger, { fontFamily: 'Pacifico-Regular' }]}

          multiline

        />

      </TestCase>

      <TestCase modal itShould="render text input with maximally 10 characters">

        <TextInputWithText style={styles.textInput} maxLength={10} />

      </TestCase>

      <TestCase modal itShould="toggle between rendering 10 and 5 characters">

        <StateKeeper

          initialValue={10}

          renderContent={(maxLength, setMaxLength) => {

            return (

              <Effect

                onMount={() => {

                  const interval = setInterval(() => {

                    setMaxLength(prev => (prev === 10 ? 5 : 10));

                  }, 1000);

                  return () => {

                    clearInterval(interval);

                  };

                }}>

                <TextInputWithText

                  style={styles.textInput}

                  maxLength={maxLength}

                  value="1234567890"

                />

              </Effect>

            );

          }}

        />

      </TestCase>

      <TestCase

        modal

        itShould="toggle between different capitalization modes"

        skip

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

      >

        <AutoCapitalize />

      </TestCase>

      <TestCase

        modal

        itShould="trigger onSubmitEditing event after submiting"

        initialState={false}

        arrange={({ setState }) => (

          <TextInputWithText

            style={styles.textInput}

            onSubmitEditing={() => setState(true)}

          />

        )}

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

          expect(state).to.be.true;

        }}

      />

      <TestCase modal itShould="toggle between different return keys">

        <ReturnKeyTypeView />

      </TestCase>

      <TestCase modal itShould="render secure text input (text obscured)">

        <TextInputWithText style={styles.textInput} secureTextEntry />

      </TestCase>

      <TestCase

        modal

        skip

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

        itShould="trigger onKeyPress event after pressing key (press 'A' to pass)"

        initialState={''}

        arrange={({ setState }) => (

          <TextInputWithText

            style={styles.textInput}

            autoFocus

            onKeyPress={event => setState(event.nativeEvent.key)}

          />

        )}

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

          expect(state).to.be.eq('A');

        }}

      />

      <TestCase modal itShould="show text input with default value">

        <DefaultProps />

      </TestCase>

      <TestCase

        modal

        itShould="trigger onLayout event on mount"

        initialState={{}}

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

          return (

            <>

              <Text>{JSON.stringify(state)}</Text>

              <TextInput

                style={styles.textInput}

                onLayout={event => {

                  setState(event.nativeEvent.layout);

                }}

              />

            </>

          );

        }}

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

          expect(state).to.include.all.keys('width', 'height', 'x', 'y');

        }}

      />

      <TestCase

        modal

        itShould="render textinputs with different keyboard types">

        <View>

          <TextInputKeyboardType keyboardType="default" />

          <TextInputKeyboardType keyboardType="number-pad" />

          <TextInputKeyboardType keyboardType="decimal-pad" />

          <TextInputKeyboardType keyboardType="numeric" />

          <TextInputKeyboardType keyboardType="email-address" />

          <TextInputKeyboardType keyboardType="phone-pad" />

          <TextInputKeyboardType keyboardType="url" />

        </View>

      </TestCase>

      <TestCase modal itShould="render textinput with allowFontScaling">

        <TextInputWithText

          style={styles.textInput}

          allowFontScaling

          defaultValue="Scaled"

        />

        <TextInputWithText

          style={styles.textInput}

          allowFontScaling={false}

          defaultValue="Not scaled"

        />

        <TextInputWithText

          style={[styles.textInput, { fontSize: 40 }]}

          allowFontScaling={true}

          defaultValue="Scaled big"

        />

        <TextInputWithText

          style={[styles.textInput, { fontSize: 40 }]}

          allowFontScaling={false}

          defaultValue="Not scaled big"

        />

      </TestCase>

      <TestCase itShould="show textInput with padding" modal>

        <View style={{ width: 300, height: 200 }}>

          <TextInputWithText

            style={{

              paddingLeft: 10,

              paddingTop: 20,

              paddingRight: 30,

              paddingBottom: 40,

              backgroundColor: 'red',

            }}

          />

        </View>

      </TestCase>

      <TestCase itShould="show textInput multiline with padding" modal>

        <View style={{ width: 300, height: 200 }}>

          <TextInputWithText

            style={{

              paddingLeft: 10,

              paddingTop: 20,

              paddingRight: 30,

              paddingBottom: 40,

              backgroundColor: 'red',

              height: 100,

            }}

            multiline

          />

        </View>

      </TestCase>

      <TestCase modal itShould="render textinput with readonly">

        {/* @ts-ignore */}

        <TextInputWithText style={styles.textInput} readOnly />

      </TestCase>

      <TestCase

        modal

        itShould="display bold, italic, large placeholder with a custom font">

        <TextInput

          style={{

            fontFamily: 'StintUltraCondensed-Regular',

            fontWeight: 'bold',

            fontSize: 24,

            fontStyle: 'italic',

          }}

          placeholder="placeholder"

        />

      </TestCase>

      <TestCase modal itShould="render textinput with red text color">

        <TextInputWithText style={[styles.textInput, { color: 'red' }]} />

      </TestCase>

      <TestCase modal itShould="clear text on focus">

        {/* iOS only */}

        <TextInputWithText style={styles.textInput} clearTextOnFocus />

      </TestCase>

    </TestSuite>

  );

}

const FocusTextInputTest = (props: {

  setState: React.Dispatch<React.SetStateAction<boolean>>;

}) => {

  const ref = useRef<TextInput>(null);

  return (

    <View>

      <Button label="focus text input" onPress={() => ref.current?.focus()} />

      <TextInput onFocus={() => props.setState(true)} ref={ref} />

    </View>

  );

};



const TextInputKeyboardType = (props: TextInputProps) => {

  return (

    <>

      <Text>{props.keyboardType}</Text>

      <TextInput

        style={{ ...styles.textInputSmall, marginBottom: 10 }}

        keyboardType={props.keyboardType}

      />

    </>

  );

};

const TextInputWithText = (props: TextInputProps) => {

  const [text, onChangeText] = useState(props.defaultValue ?? '');

  return (

    <>

      <Text style={styles.text}>{text}</Text>

      <TextInput {...props} onChangeText={onChangeText} value={text} />

    </>

  );

};

type CapitalizationType = 'none' | 'sentences' | 'words' | 'characters';

const AutoCapitalize = () => {

  const [state, setState] = useState<CapitalizationType>('none');

  const capitalizations: Array<CapitalizationType> = [

    'none',

    'sentences',

    'words',

    'characters',

  ];

  const toggleCapitalization = () => {

    const index = capitalizations.indexOf(state);

    setState(capitalizations[(index + 1) % capitalizations.length]);

  };

  return (

    <>

      <TextInputWithText style={styles.textInput} autoCapitalize={state} />

      <Button label="toggle capitalize mode" onPress={toggleCapitalization} />

      <Text>Capitalize mode: {state}</Text>

    </>

  );

};

const ReturnKeyTypeView = () => {

  const [state, setState] = useState<ReturnKeyType | ReturnKeyTypeAndroid>(

    'none',

  );

  const returnKey: Array<ReturnKeyType | ReturnKeyTypeAndroid> = [

    'none',

    'done',

    'go',

    'next',

    'search',

    'send',

    'none',

    'previous', //currently not supported by ArkUI

  ];

  const toggleReturnKey = () => {

    const index = returnKey.indexOf(state);

    setState(returnKey[(index + 1) % returnKey.length]);

  };

  return (

    <>

      <TextInputWithText style={styles.textInput} returnKeyType={state} />

      <Button label="toggle return key type" onPress={toggleReturnKey} />

      <Text>Return key: {state}</Text>

    </>

  );

};



const DefaultProps = () => {

  // @ts-ignore

  TextInput.defaultProps = {

    value: 'defaultText',

  };



  return <TextInput style={styles.textInput} />;

};



const styles = StyleSheet.create({

  container: {

    width: 80,

    height: 80,

    backgroundColor: 'red',

  },

  text: {

    width: '100%',

    height: 40,

  },

  textInputSmall: {

    height: 20, // hack

    fontSize: 8,

    color: 'black',

    backgroundColor: 'rgb(245, 240, 211)',

    borderRadius: 20,

  },

  textInput: {

    height: 40, // hack

    fontSize: 16,

    color: 'black',

    backgroundColor: 'rgb(245, 240, 211)',

    borderRadius: 40,

  },

  textInputBigger: {

    height: 80, // hack

    fontSize: 16,

    color: 'black',

    backgroundColor: 'rgb(245, 240, 211)',

    borderRadius: 20,

  },

});