/**
 * Copyright (c) 2026 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 {
  EnterKeyHintType,
  EnterKeyHintTypeAndroid,
  type EmitterSubscription,
  KeyboardTypeOptions,
  Platform,
  Keyboard,
  ReturnKeyType,
  ReturnKeyTypeAndroid,
  StyleSheet,
  Text,
  TextInput,
  TextInputProps,
  View,
  Image,
} from 'react-native';
import {TestSuite} from '@rnoh/testerino';
import React, {useState, useRef, createRef, forwardRef, useEffect} from 'react';
import {Button, Effect, StateKeeper, TestCase} from '../components';
import {useEnvironment} from '../contexts';

const KEYBOARD_TYPES: KeyboardTypeOptions[] = [
  'default',
  'number-pad',
  'decimal-pad',
  'numeric',
  'email-address',
  'phone-pad',
  'url',
];

const TEXTS = [
  'Text content',
  'Hello, World!',
  'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
];

const expectKeyboardToAppear = (timeout = 500): Promise<void> => {
  return new Promise<void>((resolve, reject) => {
    let keyboardListener: EmitterSubscription | undefined;
    const timeoutId = setTimeout(() => {
      keyboardListener?.remove();
      reject(new Error(`Keyboard did not show within ${timeout}ms`));
    }, timeout);

    keyboardListener = Keyboard.addListener('keyboardDidShow', () => {
      keyboardListener?.remove();
      clearTimeout(timeoutId);
      resolve();
    });
  });
};

const expectKeyboardToRemainHidden = (timeout = 500): Promise<void> => {
  return new Promise<void>((resolve, reject) => {
    let keyboardListener: EmitterSubscription | undefined;
    const timeoutId = setTimeout(() => {
      keyboardListener?.remove();
      resolve();
    }, timeout);

    keyboardListener = Keyboard.addListener('keyboardDidShow', () => {
      keyboardListener?.remove();
      clearTimeout(timeoutId);
      reject(new Error('Keyboard showed unexpectedly'));
    });
  });
};

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

  return (
    <TestSuite name="TextInput">
      <TestCase.Automated
        itShould="render textinput and change the text component based on the values inputted"
        tags={['sequential']}
        initialState={{
          text: '',
          ref: createRef<TextInput>(),
        }}
        arrange={({setState, state, done}) => (
          <TextInputWithText
            style={styles.textInput}
            ref={state.ref}
            onEndEditing={done}
            onChangeText={text => {
              setState(prev => ({...prev, text}));
            }}
          />
        )}
        act={async ({state, done}) => {
          await driver?.inputText(state.ref, 'ab');
          done();
          Keyboard.dismiss();
        }}
        assert={({expect, state}) => {
          expect(state.text).to.be.equal('ab');
        }}
      />
      <TestCase.Automated
        itShould="not crash when invalid keyboardType is supplied"
        tags={['sequential']}
        initialState={{
          keyboardOpened: false,
          ref: createRef<TextInput>(),
        }}
        arrange={({state}) => (
          <TextInputWithText style={styles.textInput} ref={state.ref} />
        )}
        act={async ({state, setState, done}) => {
          if (state.ref?.current) {
            try {
              state.ref.current.focus();

              await expectKeyboardToAppear();

              setState(prev => ({...prev, keyboardOpened: true}));
            } catch (error) {
              console.error(error);
            } finally {
              Keyboard.dismiss();
              done();
            }
          }
        }}
        assert={({expect, state}) => {
          expect(state.keyboardOpened).to.be.equal(true);
        }}
      />
      <TestCase.Automated
        itShould="render textinput with set content"
        tags={['sequential']}
        initialState={{
          index: 0, // Which TEXTS item is currently sent to the component
          collectedTexts: [] as string[], // What the component reported back via onRendered
        }}
        arrange={({state, setState}) => (
          <TextInputWithTextContent
            style={styles.textInput}
            content={TEXTS[state.index]}
            onRendered={text =>
              setState(prev => ({
                ...prev,
                collectedTexts: [...prev.collectedTexts, text],
              }))
            }
          />
        )}
        act={async ({setState, done}) => {
          await new Promise(res => setTimeout(res, 500));
          for (let i = 0; i < 3; i++) {
            setState(prev => ({
              ...prev,
              index: (prev.index + 1) % TEXTS.length,
            }));
            await new Promise(res => setTimeout(res, 500));
          }
          done();
        }}
        assert={({expect, state}) => {
          expect(state.collectedTexts).to.deep.equal([
            'Text content',
            'Hello, World!',
            'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
            'Text content',
          ]);
        }}
      />
      <TestCase.Automated
        itShould="render non-editable textInput"
        tags={['sequential']}
        initialState={{
          ref: createRef<TextInput>(),
        }}
        arrange={({state}) => (
          <TextInputWithText
            defaultValue="test"
            style={styles.textInput}
            editable={false}
            ref={state.ref}
          />
        )}
        act={async ({state, done}) => {
          if (state.ref?.current) {
            try {
              state.ref.current.focus();
              await expectKeyboardToRemainHidden();
            } catch (error) {
              console.error(error);
            } finally {
              done();
            }
          }
        }}
        assert={({expect}) => {
          expect(Keyboard.isVisible()).to.be.equal(false);
        }}
      />
      <TestCase.Example
        modal
        itShould="should log only once, after pressing space">
        <TextInput
          style={styles.textInput}
          value={' '}
          onChangeText={text => {
            console.log('text=', text);
          }}
        />
      </TestCase.Example>
      <TestCase.Example itShould="render textInput with Pacifico Regular font">
        <TextInputWithText
          style={[styles.textInput, {fontFamily: 'Pacifico-Regular'}]}
        />
      </TestCase.Example>
      <TestCase.Example itShould="render textInput with caret hidden">
        <TextInputWithText style={styles.textInput} caretHidden />
      </TestCase.Example>
      <TestCase.Example itShould="render textInput with red caret">
        <TextInputWithText style={styles.textInput} cursorColor={'red'} />
      </TestCase.Example>
      <TestCase.Automated
        itShould="report content size changes (onContentSizeChange)"
        tags={['sequential']}
        initialState={{
          contentSizeChanged: false,
          ref: createRef<TextInput>(),
        }}
        arrange={({state, setState}) => (
          <TextInputWithText
            style={styles.textInput}
            multiline
            ref={state.ref}
            onContentSizeChange={() => {
              setState(prev => ({...prev, contentSizeChanged: true}));
            }}
          />
        )}
        act={async ({state, done}) => {
          await driver?.inputText(state.ref, 'abc');
          done();
        }}
        assert={({expect, state}) => {
          expect(state.contentSizeChanged).to.be.true;
        }}
      />
      <TestSuite name="focus/blur">
        <TestCase.Automated
          itShould="blur text on submit (singleline)"
          tags={['sequential']}
          initialState={{
            ref: createRef<TextInput>(),
            blurred: false,
          }}
          arrange={({state, setState}) => (
            <TextInputWithText
              style={styles.textInput}
              submitBehavior="blurAndSubmit"
              ref={state.ref}
              onBlur={() => {
                setState(prev => ({...prev, blurred: true}));
              }}
            />
          )}
          act={async ({done, state}) => {
            await driver?.inputText(state.ref, 'abc');
            await driver?.keyEvent().key('Enter').send();
            done();
          }}
          assert={({expect, state}) => {
            expect(state.blurred).to.be.equal(true);
          }}
        />
        <TestCase.Automated
          itShould="blur text on submit (multiline)"
          tags={['sequential']}
          initialState={{
            ref: createRef<TextInput>(),
            blurred: false,
          }}
          arrange={({state, setState}) => (
            <TextInputWithText
              style={styles.textInput}
              submitBehavior="blurAndSubmit"
              multiline
              ref={state.ref}
              onBlur={() => {
                setState(prev => ({...prev, blurred: true}));
              }}
            />
          )}
          act={async ({state, done}) => {
            await driver?.inputText(state.ref, 'abc');
            await driver?.keyEvent().key('Enter').send();
            done();
          }}
          assert={({expect, state}) => {
            expect(state.blurred).to.be.equal(true);
          }}
        />
        <TestCase.Automated
          itShould="blur text after switching to another textinput"
          tags={['sequential']}
          initialState={{
            firstTextInputRef: createRef<TextInput>(),
            secondTextInputRef: createRef<TextInput>(),
            blurredFirstRef: false,
          }}
          arrange={({state, setState}) => (
            <>
              <TextInputWithText
                style={styles.textInput}
                ref={state.firstTextInputRef}
                onBlur={() => {
                  setState(prev => ({...prev, blurredFirstRef: true}));
                }}
              />
              <TextInputWithText
                style={styles.textInput}
                ref={state.secondTextInputRef}
              />
            </>
          )}
          act={async ({state, done}) => {
            await driver?.inputText(state.firstTextInputRef, 'abc');
            await driver?.inputText(state.secondTextInputRef, 'abc');

            done();
          }}
          assert={({expect, state}) => {
            expect(state.blurredFirstRef).to.be.equal(true);
          }}
        />
        <TestCase.Automated
          itShould="not blur text on submit (singleline)"
          tags={['sequential']}
          initialState={{
            ref: createRef<TextInput>(),
            blurred: false,
          }}
          arrange={({state, setState}) => (
            <TextInputWithText
              style={styles.textInput}
              submitBehavior="submit"
              ref={state.ref}
              onBlur={() => {
                setState(prev => ({...prev, blurred: true}));
              }}
            />
          )}
          act={async ({state, done}) => {
            await driver?.inputText(state.ref, 'abc');
            await driver?.keyEvent().key('Enter').send();
            done();
          }}
          assert={({expect, state}) => {
            expect(state.blurred).to.be.equal(false);
          }}
        />
        <TestCase.Automated
          itShould="not blur text on submit (multiline)"
          tags={['sequential']}
          initialState={{
            ref: createRef<TextInput>(),
            blurred: false,
          }}
          arrange={({state, setState}) => (
            <TextInputWithText
              style={styles.textInput}
              submitBehavior="submit"
              multiline
              ref={state.ref}
              onBlur={() => {
                setState(prev => ({...prev, blurred: true}));
              }}
            />
          )}
          act={async ({state, done}) => {
            await driver?.inputText(state.ref, 'abc');
            await driver?.keyEvent().key('Enter').send();
            done();
          }}
          assert={({expect, state}) => {
            expect(state.blurred).to.be.equal(false);
          }}
        />
        <TestCase.Manual
          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.Manual
          modal
          itShould="automatically focus textInput (multiline) when displayed"
          initialState={false}
          arrange={({setState}) => (
            <TextInputWithText
              style={styles.textInput}
              multiline
              autoFocus
              onFocus={() => setState(true)}
            />
          )}
          assert={({expect, state}) => {
            expect(state).to.be.true;
          }}
        />
        <TestCase.Automated
          itShould="focus textInput on click"
          tags={['sequential']}
          initialState={{
            ref: createRef<TextInput>(),
            focused: false,
          }}
          arrange={({state, setState}) => (
            <TextInput
              style={styles.textInput}
              ref={state.ref}
              onFocus={() => {
                setState(prev => ({...prev, focused: true}));
              }}
            />
          )}
          act={async ({done, state}) => {
            await driver?.click({ref: state.ref});
            try {
              await expectKeyboardToAppear();
            } catch (error) {
              console.error(error);
            } finally {
              done();
            }
          }}
          assert={({expect, state}) => {
            expect(state.focused).to.be.true;
          }}
        />
        <TestCase.Automated
          itShould="focus textInput when pressing the button"
          tags={['sequential']}
          initialState={{
            buttonRef: createRef<View>(),
            focused: false,
          }}
          arrange={({state, setState}) => (
            <FocusTextInputTest
              setFocused={() => setState(prev => ({...prev, focused: true}))}
              ref={state.buttonRef}
            />
          )}
          act={async ({done, state}) => {
            await driver?.click({ref: state.buttonRef});
            try {
              await expectKeyboardToAppear();
            } catch (error) {
              console.error(error);
            } finally {
              done();
            }
          }}
          assert={({expect, state}) => {
            expect(state.focused).to.be.true;
          }}
        />
      </TestSuite>
      <TestCase.Example itShould="render textinput with red placeholder">
        <TextInputWithText
          style={styles.textInput}
          placeholder="Placeholder"
          placeholderTextColor={'red'}
        />
      </TestCase.Example>
      <TestCase.Example itShould="render textinput with default selection color">
        <TextInputWithText style={styles.textInput} />
      </TestCase.Example>
      <TestCase.Example itShould="render textinput with green selection color">
        <TextInputWithText style={styles.textInput} selectionColor="green" />
      </TestCase.Example>
      <TestCase.Example itShould="render textinput with blue underline color">
        <TextInputWithText
          style={styles.textInput}
          underlineColorAndroid={'blue'}
        />
      </TestCase.Example>
      <TestCase.Automated
        itShould="not open the keyboard after focusing"
        tags={['sequential']}
        initialState={{
          ref: createRef<TextInput>(),
        }}
        arrange={({state}) => (
          <TextInputWithText
            style={styles.textInput}
            ref={state.ref}
            showSoftInputOnFocus={false}
          />
        )}
        act={async ({done, state}) => {
          await driver?.click({ref: state.ref});
          try {
            await expectKeyboardToRemainHidden();
          } catch (error) {
            console.error(error);
          } finally {
            done();
          }
        }}
        assert={({expect}) => {
          expect(Keyboard.isVisible()).to.be.false;
        }}
      />
      <TestCase.Example itShould="render multiline text input">
        <TextInputWithText style={styles.textInputBigger} multiline />
      </TestCase.Example>
      <TestCase.Example itShould="render multiline text input with common border">
        <TextInputWithText style={styles.multilineInput} multiline />
      </TestCase.Example>
      <TestCase.Example itShould="render multiline text input with Pacifico Regular font">
        <TextInputWithText
          style={[styles.textInputBigger, {fontFamily: 'Pacifico-Regular'}]}
          multiline
        />
      </TestCase.Example>
      <TestCase.Automated
        itShould="render text input with maximally 10 characters"
        tags={['sequential']}
        initialState={{
          ref: createRef<TextInput>(),
          text: '',
        }}
        arrange={({state, setState}) => (
          <TextInputWithText
            style={styles.textInput}
            ref={state.ref}
            maxLength={10}
            onChangeText={text => {
              setState(prev => ({...prev, text}));
            }}
          />
        )}
        act={async ({done, state}) => {
          await driver?.inputText(state.ref, '01234567891011');
          done();
        }}
        assert={({expect, state}) => {
          expect(state.text).to.be.equal('0123456789');
        }}
      />
      <TestCase.Example
        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}
                  defaultValue="1234567890"
                />
              </Effect>
            );
          }}
        />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="toggle between different capitalization modes"
        skip={{android: false, harmony: true}}
        //https://gl.swmansion.com/rnoh/react-native-harmony/-/issues/408
      >
        <AutoCapitalize />
      </TestCase.Example>
      <TestCase.Automated
        itShould="trigger onSubmitEditing event after submiting"
        tags={['sequential']}
        initialState={{
          ref: createRef<TextInput>(),
          submitted: false,
        }}
        arrange={({state, setState}) => (
          <TextInputWithText
            style={styles.textInput}
            ref={state.ref}
            onSubmitEditing={() =>
              setState(prev => ({...prev, submitted: true}))
            }
          />
        )}
        act={async ({done, state}) => {
          await driver?.inputText(state.ref, 'abc');
          await driver?.keyEvent().key('Enter').send();
          done();
        }}
        assert={({expect, state}) => {
          expect(state.submitted).to.be.true;
        }}
      />
      <TestCase.Example modal itShould="toggle between different return keys">
        <ReturnKeyTypeView />
      </TestCase.Example>
      <TestSuite name="returnKeyLabel">
        <TestCase.Example itShould="display a proper label for the keyboard 'submit' button">
          <TextInput
            value="<default>: 完成 (en: complete)"
            style={{padding: 16, borderWidth: StyleSheet.hairlineWidth}}
          />
          <TextInput
            returnKeyLabel="search"
            value="'search': 搜索 (en: search)"
            style={{padding: 16, borderWidth: StyleSheet.hairlineWidth}}
          />
        </TestCase.Example>
      </TestSuite>
      <TestCase.Example modal itShould="toggle between different enter keys">
        <EnterKeyHintExample />
      </TestCase.Example>
      <TestCase.Example itShould="render secure text input with no password Icon (text obscured)">
        <Text>Please pay attention to whether the style is correct</Text>
        <Image
          source={require('../assets/textinput_secure_style.png')}
          style={{width: '100%'}}
          resizeMode="contain"
        />
        <Text>e.g</Text>
        <TextInputWithText style={styles.textInput} secureTextEntry />
      </TestCase.Example>
      <TestCase.Automated
        itShould="trigger onKeyPress event after pressing key (press 'A' to pass)"
        tags={['sequential']}
        initialState={{
          ref: createRef<TextInput>(),
          key: '',
        }}
        arrange={({state, setState}) => (
          <TextInputWithText
            style={styles.textInput}
            ref={state.ref}
            onKeyPress={event => {
              const key = event.nativeEvent.key;
              setState(prev => ({...prev, key}));
            }}
          />
        )}
        act={async ({done, state}) => {
          await driver?.inputText(state.ref, 'a');
          done();
        }}
        assert={({expect, state}) => {
          expect(state.key).to.be.eq('a');
        }}
      />
      <TestCase.Manual
        modal
        itShould="trigger onKeyPress event after pressing key with Chinese Character (press 'ha' and select '哈' to pass)"
        initialState={''}
        arrange={({setState}) => (
          <TextInputWithText
            style={styles.textInput}
            autoFocus
            onKeyPress={event => {
              setState(event.nativeEvent.key);
            }}
          />
        )}
        assert={({expect, state}) => {
          expect(state).to.be.eq('哈');
        }}
      />
      <TestCase.Automated
        itShould="trigger onKeyPress event after pressing backspace"
        tags={['sequential']}
        initialState={{
          firstTextInputKey: '',
          secondTextInputKey: '',
          firstTextInputRef: createRef<TextInput>(),
          secondTextInputRef: createRef<TextInput>(),
        }}
        arrange={({state, setState}) => (
          <>
            <TextInputWithText
              style={styles.textInput}
              autoFocus
              defaultValue="a"
              ref={state.firstTextInputRef}
              onKeyPress={event => {
                const firstTextInputKey = event.nativeEvent.key;
                setState(prev => ({
                  ...prev,
                  firstTextInputKey,
                }));
              }}
            />
            <TextInputWithText
              style={styles.textInputBigger}
              multiline
              defaultValue="a"
              ref={state.secondTextInputRef}
              onKeyPress={event => {
                const secondTextInputKey = event.nativeEvent.key;
                setState(prev => ({
                  ...prev,
                  secondTextInputKey,
                }));
              }}
            />
          </>
        )}
        act={async ({done, state}) => {
          state.firstTextInputRef.current?.focus();
          await driver?.keyEvent().key('Backspace').send();
          state.secondTextInputRef.current?.focus();
          await driver?.keyEvent().key('Backspace').send();
          done();
        }}
        assert={({expect, state}) => {
          expect(state.firstTextInputKey).to.be.eq('Backspace');
          expect(state.secondTextInputKey).to.be.eq('Backspace');
        }}
      />
      <TestCase.Automated
        itShould="trigger onKeyPress event after pressing backspace when the text input is empty"
        tags={['sequential']}
        initialState={{
          firstTextInputKey: '',
          secondTextInputKey: '',
          firstTextInputRef: createRef<TextInput>(),
          secondTextInputRef: createRef<TextInput>(),
        }}
        arrange={({state, setState}) => (
          <>
            <TextInputWithText
              style={styles.textInput}
              autoFocus
              defaultValue=""
              ref={state.firstTextInputRef}
              onKeyPress={event => {
                const firstTextInputKey = event.nativeEvent.key;
                setState(prev => ({
                  ...prev,
                  firstTextInputKey,
                }));
              }}
            />
            <TextInputWithText
              style={styles.textInputBigger}
              multiline
              defaultValue=""
              ref={state.secondTextInputRef}
              onKeyPress={event => {
                const secondTextInputKey = event.nativeEvent.key;
                setState(prev => ({
                  ...prev,
                  secondTextInputKey,
                }));
              }}
            />
          </>
        )}
        act={async ({done, state}) => {
          state.firstTextInputRef.current?.focus();
          await driver?.keyEvent().key('Backspace').send();
          state.secondTextInputRef.current?.focus();
          await driver?.keyEvent().key('Backspace').send();
          done();
        }}
        assert={({expect, state}) => {
          expect(state.firstTextInputKey).to.be.eq('Backspace');
          expect(state.secondTextInputKey).to.be.eq('Backspace');
        }}
      />
      <TestCase.Manual
        modal
        itShould="trigger onKeyPress for a non-ASCII input (press 'a' to pass)"
        initialState={''}
        arrange={({setState}) => (
          <>
            <TextInputWithText
              style={styles.textInput}
              autoFocus
              defaultValue="你好😊"
              onKeyPress={event => setState(event.nativeEvent.key)}
            />
          </>
        )}
        assert={({expect, state}) => {
          expect(state).to.be.eq('a');
        }}
      />
      <TestCase.Automated
        itShould="show text input with default value (defaultProps)"
        tags={['sequential']}
        initialState={{
          ref: createRef<TextInput>(),
          text: '',
        }}
        arrange={({state, setState}) => (
          <DefaultProps
            ref={state.ref}
            defaultValue="defaultText"
            onSubmitEditing={e => {
              const text = e.nativeEvent.text;
              setState(prev => ({...prev, text}));
            }}
          />
        )}
        act={async ({done, state}) => {
          state.ref.current?.focus();
          await driver?.keyEvent().key('Enter').send();
          done();
        }}
        assert={({expect, state}) => {
          expect(state.text).to.be.eq('defaultText');
        }}
      />
      <TestCase.Automated
        itShould="show text input with default value (defaultValue)"
        tags={['sequential']}
        initialState={{
          ref: createRef<TextInput>(),
          text: '',
        }}
        arrange={({state, setState}) => (
          <TextInput
            style={styles.textInput}
            defaultValue="defaultText"
            ref={state.ref}
            onSubmitEditing={e => {
              const text = e.nativeEvent.text;
              setState(prev => ({...prev, text}));
            }}
          />
        )}
        act={async ({done, state}) => {
          state.ref.current?.focus();
          await driver?.keyEvent().key('Enter').send();
          done();
        }}
        assert={({expect, state}) => {
          expect(state.text).to.be.eq('defaultText');
        }}
      />
      <TestCase.Automated
        itShould="trigger onLayout event on mount"
        initialState={{}}
        tags={['sequential']}
        arrange={({setState, state}) => {
          return (
            <>
              <Text>{JSON.stringify(state)}</Text>
              <TextInput
                style={styles.textInput}
                onLayout={event => {
                  setState(event.nativeEvent.layout);
                }}
              />
            </>
          );
        }}
        act={async ({done}) => {
          // Event was received after done()
          await new Promise(resolve => setTimeout(resolve, 1000));
          done();
        }}
        assert={({expect, state}) => {
          expect(state).to.include.all.keys('width', 'height', 'x', 'y');
        }}
      />
      <TestCase.Example
        modal
        itShould="render textinputs with different keyboard types">
        <View>
          {KEYBOARD_TYPES.map(type => (
            <TextInputKeyboardType
              key={`singleline_${type}`}
              keyboardType={type}
            />
          ))}
        </View>
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="render multiline textinputs with different keyboard types">
        <View>
          {KEYBOARD_TYPES.map(type => (
            <TextInputKeyboardType
              key={`multiline_${type}`}
              keyboardType={type}
              multiline
            />
          ))}
        </View>
      </TestCase.Example>
      <TestCase.Example 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.Example>
      <TestCase.Example
        modal
        itShould="render textinput with different maxFontSizeMultiplier (change font scale in settings)">
        <TextInput
          style={styles.textInput}
          allowFontScaling={false}
          defaultValue="Non scaled"
        />
        <TextInput
          style={styles.textInput}
          defaultValue="maxFontSizeMultiplier 1.2"
          allowFontScaling
          maxFontSizeMultiplier={1.2}
        />
        <TextInput
          style={styles.textInput}
          defaultValue="maxFontSizeMultiplier 1.4"
          allowFontScaling
          maxFontSizeMultiplier={1.4}
        />
        <TextInput
          style={styles.textInput}
          allowFontScaling={true}
          maxFontSizeMultiplier={0}
          defaultValue="Scaled without limit"
        />
      </TestCase.Example>
      <TestCase.Example 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.Example>
      <TestCase.Example 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.Example>
      <TestCase.Automated
        itShould="render textinput with readonly"
        tags={['sequential']}
        initialState={{
          ref: createRef<TextInput>(),
        }}
        arrange={({state}) => (
          <TextInputWithText
            defaultValue="readOnly"
            style={styles.textInput}
            readOnly={true}
            ref={state.ref}
          />
        )}
        act={async ({state, done}) => {
          if (state.ref?.current) {
            try {
              state.ref.current.focus();
              await expectKeyboardToRemainHidden();
            } catch (error) {
              console.error(error);
            } finally {
              done();
            }
          }
        }}
        assert={({expect}) => {
          expect(Keyboard.isVisible()).to.be.equal(false);
        }}
      />
      <TestCase.Example
        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.Example>
      <TestCase.Example modal itShould="render textinput with red text color">
        <TextInputWithText style={[styles.textInput, {color: 'red'}]} />
      </TestCase.Example>
      <TestCase.Automated
        skip={{android: true, harmony: false}}
        itShould="clear text on focus"
        tags={['sequential']}
        initialState={{
          ref: createRef<TextInput>(),
          text: '',
        }}
        arrange={({state, setState}) => (
          <TextInputWithText
            style={styles.textInput}
            ref={state.ref}
            defaultValue=""
            selectTextOnFocus
            onChange={event => {
              const text = event.nativeEvent.text;
              setState(prev => ({...prev, text}));
            }}
            clearTextOnFocus
          />
        )}
        act={async ({done, state}) => {
          state.ref.current?.focus();
          try {
            await expectKeyboardToAppear();
          } catch (error) {
            console.error(error);
          } finally {
            done();
          }
        }}
        assert={({expect, state}) => {
          expect(state.text).to.be.equal('');
        }}
      />
      <TestCase.Automated
        skip={{android: true, harmony: false}}
        itShould="When the TextInput is unmounted, other components will not gain focus passively.​"
        tags={['sequential']}
        initialState={{
          inputRef: createRef<TextInput>(),
          show: true,
          firstFocus: false,
          secondFocus: false,
        }}
        arrange={({state, setState}) => (
          <View collapsable={false} style={{gap: 10}}>
            <TextInput
              ref={state.inputRef}
              placeholder="TextInput1"
              style={{backgroundColor: 'pink', height: 40}}
              onFocus={() => {
                setState(prev => ({...prev, firstFocus: true}));
              }}
            />
            <TextInput
              placeholder="TextInput2"
              style={{backgroundColor: 'orange', height: 40}}
              onFocus={() => {
                setState(prev => ({...prev, secondFocus: true}));
              }}
            />
            {state.show ? (
              <TextInput
                placeholder="TextInput3"
                autoFocus={true}
                style={{backgroundColor: 'blue', height: 40}}
              />
            ) : null}
          </View>
        )}
        act={async ({done, state, setState}) => {
          setTimeout(() => {
            setState(prev => ({...prev, show: false}));
          }, 300);
          setTimeout(() => {
            setState(prev => ({...prev, show: true}));
          }, 400);
          setTimeout(() => {
            setState(prev => ({...prev, show: false}));
            state.inputRef.current?.focus();
          }, 500);
          setTimeout(() => {
            done();
          }, 600);
        }}
        assert={({expect, state}) => {
          expect(state.firstFocus).to.be.true;
          expect(state.secondFocus).to.be.false;
        }}
      />
      <TestCase.Example
        // Only "unless-editing" mode doesn't work on C_API
        modal
        itShould="use different clearButtonMode values">
        <TextInputWithText style={styles.textInput} clearButtonMode="always" />
        <Text>clearButtonMode="always"</Text>
        {
          /* Except Android */
          Platform.OS !== 'android' && (
            <>
              <TextInputWithText
                style={styles.textInput}
                clearButtonMode="while-editing"
              />
              <Text>clearButtonMode="while-editing"</Text>
              <TextInputWithText
                style={styles.textInput}
                clearButtonMode="unless-editing"
              />
              <Text>clearButtonMode="unless-editing"</Text>
            </>
          )
        }
        <TextInputWithText style={styles.textInput} clearButtonMode="never" />
        {/* You cannot see inputs with */}
        <Text style={{marginBottom: 200}}>clearButtonMode="never"</Text>
      </TestCase.Example>
      <TestCase.Example modal itShould="show selection start and end values">
        <TextSelectionChangeTest />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="show textinput with 'Selection' substring selected">
        <SelectionTest />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="show controlled textinput with 'Selection' substring selected">
        <ControlledSelectionTest />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="not show text context menu when long press">
        <ContextMenuHiddenTest />
      </TestCase.Example>
      <TestCase.Example modal itShould="select text on focus">
        <TextInput
          value="selectTextOnFocus"
          selectTextOnFocus
          style={styles.textInput}
        />
        <TextInput
          value={'selectTextOnFocus \n but multiline'}
          selectTextOnFocus
          multiline
          style={[styles.textInputBigger, {marginTop: 10}]}
        />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="allow to change the text input value via props">
        <TextInputValueSetProgrammatically />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="should show transparent TextInput on a red background">
        <View style={{backgroundColor: 'red'}}>
          <TextInput
            value="parent is red but I am transparent"
            style={{height: 40}}
          />
        </View>
      </TestCase.Example>
      <TestSuite name="style">
        {createSingleAndMultilineTest(
          'display light cyan background text input with larger line height than the reddish text input',
          (name, multiline) => {
            return (
              <TestCase.Example
                itShould={name}
                skip={{
                  android: false,
                  harmony: {
                    arkTs: true,
                    cAPI: multiline
                      ? "text should be vertically aligned (to match Android); spacing between wrapped lines isn't correct — those issues seem like a platform issue"
                      : false,
                  },
                }}>
                <TextInput
                  multiline={multiline}
                  defaultValue="lineHeight: 128"
                  style={{lineHeight: 128, backgroundColor: 'lightcyan'}}
                />
                <TextInput
                  defaultValue="lineHeight: undefined"
                  multiline={multiline}
                  style={{backgroundColor: 'mistyrose'}}
                />
              </TestCase.Example>
            );
          },
        )}
      </TestSuite>
      <TestCase.Manual
        modal
        itShould="trigger onEndEditing event after editing ends"
        initialState={false}
        arrange={({setState}) => (
          <TextInputWithText
            style={styles.textInput}
            autoFocus
            onEndEditing={() => setState(true)}
          />
        )}
        assert={({expect, state}) => {
          expect(state).to.be.true;
        }}
      />
      <TestCase.Manual
        modal
        itShould="trigger onChange event after changing value"
        initialState={false}
        arrange={({setState}) => (
          <TextInputWithText onChange={() => setState(true)} />
        )}
        assert={({expect, state}) => {
          expect(state).to.be.true;
        }}
      />
      <TestCase.Example
        modal
        itShould="set cursorColor to red after pressing button (setNativeProps)">
        <SetNativePropsTest />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="select only Selection word (selectTextOnFocus && selection)">
        <TextInput
          style={styles.textInput}
          selection={{start: 4, end: 13}}
          value="TextSelectionTest"
          selectTextOnFocus
        />
      </TestCase.Example>
      <TestCase.Manual
        modal
        itShould="not trigger onChange event after changing value through state"
        initialState={{text: '', onChangeFired: false}}
        arrange={({setState, state}) => {
          return (
            <View>
              <TextInput
                style={styles.textInput}
                value={state.text}
                onChange={() => {
                  setState(prev => ({...prev, onChangeFired: true}));
                }}
              />
              <Button
                label="change text"
                onPress={() =>
                  setState(prev => ({...prev, text: prev.text + 'a'}))
                }
              />
            </View>
          );
        }}
        assert={({expect, state}) => {
          expect(state.onChangeFired).to.be.false;
          expect(state.text).to.not.be.equal('');
        }}
      />
      <TestCase.Example
        modal
        itShould="change the text input value programmatically on blur">
        <TextInputValueSetProgrammaticallyOnBlur />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="change the text input value programmatically when submitted">
        <TextInputValueSetProgrammaticallyWhenSubmitted />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="render textinput textinputs with different InputMode types">
        <TextInputInputModeTest />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="render multiline with different InputMode types">
        <TextAreaInputModeTest />
      </TestCase.Example>
      <TestCase.Example itShould="when value is set and entering Chinese, the cursor position is at the correct position">
        <TextInput
          placeholder="Please Enter Text"
          value="Enter a piece of Chinese text at any position"
          style={{borderWidth: 1, height: 50}}
        />
      </TestCase.Example>
      <TestCase.Manual
        itShould="not trigger backspace event after pressing any other key"
        initialState={''}
        arrange={({setState}) => (
          <TextInput
            style={styles.textInput}
            value={''}
            onKeyPress={event => setState(event.nativeEvent.key)}
          />
        )}
        assert={({expect, state}) => {
          expect(state).to.not.be.equal('Backspace');
        }}
      />
      <TestCase.Example
        modal
        itShould="When entering a bank card number, the cursor should
        automatically move past the space after encountering one.">
        <TextInputBankCardNumber />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="cursor should be at the end when focusing a textinput with value">
        <FocusWithCursorTest />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="show textinput with predefined selection">
        <SelectionTestComponent />
      </TestCase.Example>
      <TestCase.Example modal itShould="display onKeyPress event data">
        <OnKeyPressTest />
      </TestCase.Example>
      <TestCase.Example modal itShould="display onChange event data">
        <OnChangeTest />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="clear textinput by calling clear method">
        <ClearButtonTest />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="format zipcode input (add dash after 5 digits)">
        <ZipCodeTextInputMask />
      </TestCase.Example>
    </TestSuite>
  );
}

const createSingleAndMultilineTest = (
  name: string,
  render: (name: string, multiline: boolean) => React.ReactElement,
) => {
  return (
    <>
      {render(name, false)}
      {render(`${name} (multiline)`, true)}
    </>
  );
};
const SetNativePropsTest = () => {
  const ref = useRef<TextInput>(null);

  return (
    <View>
      <TextInput cursorColor={'blue'} ref={ref} />
      <Button
        label="setCursorColor"
        onPress={() => ref.current?.setNativeProps({cursorColor: 'red'})}
      />
    </View>
  );
};

const SelectionTest = () => {
  return (
    <View>
      <TextInput
        style={styles.textInput}
        value="TextSelectionTest"
        selection={{start: 4, end: 13}}
      />
      <TextInput
        style={[styles.textInputBigger, {marginTop: 10}]}
        value={'TextSelect\nionTest'}
        selection={{start: 4, end: 13}}
        multiline
      />
    </View>
  );
};

const ContextMenuHiddenTest = () => {
  return (
    <View>
      <TextInput
        style={styles.textInput}
        value="ContextMenuHiddenTest"
        contextMenuHidden={true}
      />
      <TextInput
        style={[styles.textInput, {marginTop: 5}]}
        value="ContextMenuHiddenTest_multiline"
        multiline
        contextMenuHidden={true}
      />
    </View>
  );
};

const TextSelectionChangeTest = () => {
  const [eventData, setEventData] = useState('');
  return (
    <View>
      <TextInput
        style={styles.textInput}
        onSelectionChange={event =>
          setEventData(JSON.stringify(event.nativeEvent.selection))
        }
      />
      <Text style={{marginVertical: 8}}>Selection {eventData}</Text>
    </View>
  );
};

interface FocusTextInputTestProps {
  setFocused: (value: boolean) => void;
}

const FocusTextInputTest = forwardRef<View, FocusTextInputTestProps>(
  (props, buttonRef) => {
    const textInputRef = useRef<TextInput>(null);
    return (
      <View>
        <Button
          label="focus text input"
          onPress={() => textInputRef.current?.focus()}
          ref={buttonRef}
        />
        <TextInput
          onFocus={() => props.setFocused(true)}
          ref={textInputRef}
          style={styles.textInput}
        />
      </View>
    );
  },
);

const TextInputKeyboardType = (props: TextInputProps) => {
  return (
    <>
      <Text>{props.keyboardType}</Text>
      <TextInput
        style={{...styles.textInputSmall, marginBottom: 10}}
        keyboardType={props.keyboardType}
        multiline={props.multiline}
      />
    </>
  );
};

/**
 * A purely-controlled TextInput that receives its text via `content`.
 * Whenever `content` changes, we inform the parent through `onRendered`.
 */
const TextInputWithTextContent = (
  props: TextInputProps & {
    content?: string;
    onRendered?: (txt: string) => void;
  },
) => {
  const text = props.content ?? TEXTS[0];

  useEffect(() => props.onRendered?.(text), [text]);

  return (
    <>
      <TextInput {...props}>{text}</TextInput>
      <Text style={{marginTop: 8, fontSize: 12, color: '#666'}}>
        The TextInput above should display:
      </Text>
      <Text style={{fontSize: 16, color: '#333'}}>{text}</Text>
    </>
  );
};

const TextInputWithText = forwardRef<TextInput, TextInputProps>(
  (props, ref) => {
    const [text, onChangeText] = useState(props.defaultValue ?? '');

    const handleChangeText = (newText: string) => {
      if (props.onChangeText) {
        props.onChangeText(newText);
      }
      onChangeText(newText);
    };

    return (
      <>
        <Text style={styles.text}>{text}</Text>
        <TextInput
          ref={ref}
          {...props}
          onChangeText={handleChangeText}
          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 EnterKeyHintExample = () => {
  const [index, setIndex] = useState(0);
  const enterKey: Array<EnterKeyHintType | EnterKeyHintTypeAndroid> = [
    'done',
    'go',
    'next',
    'previous',
    'search',
    'send',
  ];
  const toggleEnterKey = () => {
    setIndex(i => (i + 1) % enterKey.length);
  };
  return (
    <>
      <TextInputWithText
        style={styles.textInput}
        enterKeyHint={enterKey[index]}
      />
      <Button label="toggle enter key type" onPress={toggleEnterKey} />
      <Text>Enter key: {enterKey[index]}</Text>
    </>
  );
};

const DefaultProps = forwardRef<TextInput, TextInputProps>((props, ref) => {
  // @ts-ignore
  TextInput.defaultProps = {
    value: props.defaultValue,
  };

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

const TextInputValueSetProgrammatically = () => {
  const [value, setValue] = useState('Default Text Input Value');

  return (
    <View style={{height: 400}}>
      <View style={{marginBottom: 16}}>
        <Button
          label="Set 'Hello, World!' as text input value "
          onPress={() => setValue('Hello, World!')}
        />
        <Button
          label="Set 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.' as text input value "
          onPress={() =>
            setValue('Lorem ipsum dolor sit amet, consectetur adipiscing elit.')
          }
        />
        <Button label="Clear text input value" onPress={() => setValue('')} />
      </View>
      <TextInput
        style={styles.textInput}
        defaultValue={value}
        value={value}
        onChangeText={setValue}
      />
    </View>
  );
};

const ControlledSelectionTest = () => {
  const [value, setValue] = useState('TextSelectionTest');
  const [valueM, setValueM] = useState('TextSelect\nionTest');

  return (
    <View>
      <TextInput
        style={styles.textInput}
        value={value}
        onChange={event => setValue(event.nativeEvent.text)}
        selection={{start: 4, end: 13}}
      />
      <TextInput
        style={[styles.textInputBigger, {marginTop: 10}]}
        value={valueM}
        onChange={event => setValueM(event.nativeEvent.text)}
        selection={{start: 4, end: 13}}
        multiline
      />
    </View>
  );
};

const TextInputValueSetProgrammaticallyOnBlur = () => {
  const [value, setValue] = useState("I'm the first text input.");

  return (
    <>
      <TextInput
        value={value}
        autoFocus
        onChangeText={text => setValue(text)}
        style={styles.textInput}
      />
      <TextInput
        onFocus={() => setValue('It works!')}
        multiline
        defaultValue="Click me and see if the value of the first text input has been changed."
        style={styles.textInputBigger}
      />
    </>
  );
};

const TextInputValueSetProgrammaticallyWhenSubmitted = () => {
  const [value, setValue] = useState('(1) Submit the text input.');

  return (
    <>
      <TextInput
        value={value}
        autoFocus
        onChangeText={text => setValue(text)}
        style={styles.textInput}
      />
      <Button
        label="(2) Press to change the text of the text input"
        onPress={() => setValue('(3) It works!')}
      />
    </>
  );
};

const TextAreaInputModeTest = () => {
  return (
    <View>
      <TextInput
        multiline
        inputMode={'none'}
        style={styles.textInput}
        placeholder={'none'}
      />
      <TextInput
        multiline
        inputMode={'text'}
        style={styles.textInput}
        placeholder={'text'}
      />
      <TextInput
        multiline
        inputMode={'decimal'}
        style={styles.textInput}
        placeholder={'decimal'}
      />
      <TextInput
        multiline
        inputMode={'numeric'}
        style={styles.textInput}
        placeholder={'numeric'}
      />
      <TextInput
        multiline
        inputMode={'tel'}
        style={styles.textInput}
        placeholder={'tel'}
      />
      <TextInput
        multiline
        inputMode={'search'}
        style={styles.textInput}
        placeholder={'search'}
      />
      <TextInput
        multiline
        inputMode={'email'}
        style={styles.textInput}
        placeholder={'email'}
      />
      <TextInput
        multiline
        inputMode={'url'}
        style={styles.textInput}
        placeholder={'url'}
      />
    </View>
  );
};

const TextInputInputModeTest = () => {
  return (
    <View>
      <TextInput
        inputMode={'none'}
        style={styles.textInput}
        placeholder={'none'}
      />
      <TextInput
        inputMode={'text'}
        style={styles.textInput}
        placeholder={'text'}
      />
      <TextInput
        inputMode={'decimal'}
        style={styles.textInput}
        placeholder={'decimal'}
      />
      <TextInput
        inputMode={'numeric'}
        style={styles.textInput}
        placeholder={'numeric'}
      />
      <TextInput
        inputMode={'tel'}
        style={styles.textInput}
        placeholder={'tel'}
      />
      <TextInput
        inputMode={'search'}
        style={styles.textInput}
        placeholder={'search'}
      />
      <TextInput
        inputMode={'email'}
        style={styles.textInput}
        placeholder={'email'}
      />
      <TextInput
        inputMode={'url'}
        style={styles.textInput}
        placeholder={'url'}
      />
    </View>
  );
};

const TextInputBankCardNumber = () => {
  const [value, setValue] = useState('');

  const handleChangeText = (text: string) => {
    let ruleArr = [3, 7];
    let newText = '';
    let ruleIndex = 0;
    if (text) {
      text = text.replace(/\D/g, '');
      text = text.split(' ').join('');
      text = text.replace(/\s+/g, '');
      for (let i = 0; i < text.length; i++) {
        if (i % ruleArr[ruleIndex] === 0 && i !== 0) {
          ruleIndex++;
          newText += ' ' + text[i];
        } else {
          newText += text[i];
        }
      }
    }
    setValue(newText);
  };

  return (
    <View>
      <TextInput
        maxLength={21}
        style={styles.textInput}
        onChangeText={handleChangeText}
        value={value}
      />
    </View>
  );
};

// Focus with cursor at position test
const FocusWithCursorTest = () => {
  const ref = useRef<TextInput>(null);
  const [value, setValue] = useState('12345');

  const handleFocus = () => {
    ref.current?.focus();
  };

  return (
    <View>
      <TextInput
        ref={ref}
        style={styles.textInput}
        value={value}
        onChangeText={setValue}
      />
      <Button label="点击后focus" onPress={handleFocus} />
    </View>
  );
};

// Selection test
const SelectionTestComponent = () => {
  return (
    <View>
      <Text>1. start less than end (选中文本): start=2, end=5</Text>
      <TextInput
        style={styles.textInput}
        defaultValue="点击输入框可以选择文字"
        selection={{start: 2, end: 5}}
      />

      <Text>2. start equals end (光标位置): start=5, end=5</Text>
      <TextInput
        style={styles.textInput}
        defaultValue="点击输入框可以选择文字"
        selection={{start: 5, end: 5}}
      />

      <Text>3. start greater than end (反向选择): start=8, end=3</Text>
      <TextInput
        style={styles.textInput}
        defaultValue="点击输入框可以选择文字"
        selection={{start: 8, end: 3}}
      />
    </View>
  );
};

// OnKeyPress test
const OnKeyPressTest = () => {
  const [value, setValue] = useState('');
  const [data, setData] = useState('');

  const handleKeyPress = (event: any) => {
    setData(event.nativeEvent.key);
  };

  return (
    <View>
      <Text>onKeyPress 参数</Text>
      <TextInput
        style={styles.textInput}
        value={value}
        onChangeText={setValue}
        onKeyPress={handleKeyPress}
      />
      <Text>keyPress内容为:{data}</Text>
    </View>
  );
};

// OnChange test
const OnChangeTest = () => {
  const [value, setValue] = useState('');
  const [onChangeData, setOnChangeData] = useState('');

  const handleChange = (text: string) => {
    setValue(text);
  };

  const handleChangeEvent = (event: any) => {
    setOnChangeData(event.nativeEvent.text);
  };

  return (
    <View>
      <Text>onChange 参数</Text>
      <TextInput
        style={styles.textInput}
        value={value}
        onChangeText={handleChange}
        onChange={handleChangeEvent}
      />
      <Text>当前输入值: {value}</Text>
      <Text>onChange内容为:{onChangeData}</Text>
    </View>
  );
};

// Clear button test
const ClearButtonTest = () => {
  const ref = useRef<TextInput>(null);
  const [value, setValue] = useState('');

  return (
    <View>
      <Text>点击按钮调用clear清空</Text>
      <TextInput
        style={styles.textInput}
        placeholder="输入输入"
        value={value}
        onChangeText={setValue}
        ref={ref}
      />
      <Button label="清空" onPress={() => ref.current?.clear()} />
    </View>
  );
};

// ZipCode format test
const ZipCodeTextInputMask = () => {
  const [code, setCode] = useState('');
  const [rawCode, setRawCode] = useState('');

  const handleCodeChange = (text: string) => {
    // 保存原始值(去除横线)
    const raw = text.replace(/-/g, '');
    setRawCode(raw);

    // 格式化:前5位后加横线
    let formatted = '';
    for (let i = 0; i < raw.length; i++) {
      if (i === 5) {
        formatted += '-' + raw[i];
      } else {
        formatted += raw[i];
      }
    }
    setCode(formatted);
  };

  return (
    <View>
      <TextInput
        value={code}
        onChangeText={handleCodeChange}
        style={styles.textInput}
        placeholder="输入邮政编码"
        keyboardType="number-pad"
      />
      <Text>格式化值: {code}</Text>
      <Text>原始值: {rawCode}</Text>

      <View style={{marginTop: 10, backgroundColor: '#f0f0f0', padding: 10}}>
        <Text style={{fontWeight: 'bold'}}>测试用例:</Text>
        <Text>输入 "123" → 期望: "123"</Text>
        <Text>输入 "12345" → 期望: "12345"</Text>
        <Text>输入 "123456" → 期望: "12345-6"</Text>
        <Text>输入 "12345678" → 期望: "12345-678"</Text>
      </View>
    </View>
  );
};

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,
  },
  multilineInput: {
    height: 80,
    borderWidth: 1,
    paddingVertical: 10,
    paddingHorizontal: 15,
    borderRadius: 5,
    marginBottom: 20,
  },
  input: {
    height: 40,
    borderColor: 'gray',
    borderWidth: 1,
    marginBottom: 16,
    paddingHorizontal: 8,
  },
});