/**
 * react-native-avoid-softinput HarmonyOS example.
 *
 * This page keeps the component path and the module path separate so the demo
 * can prove the same API surface exposed by upstream Android/RN code.
 */
import * as React from 'react';
import {
  Platform,
  SafeAreaView,
  ScrollView,
  StyleSheet,
  Text,
  TextInput,
  TouchableOpacity,
  TurboModuleRegistry,
  View,
} from 'react-native';
import type { TurboModule } from 'react-native';
import { AvoidSoftInput, AvoidSoftInputView, useSoftInputState } from '@hxa-rn/react-native-avoid-softinput';
import type { SoftInputEasing } from '@hxa-rn/react-native-avoid-softinput';

const EASINGS: SoftInputEasing[] = ['linear', 'easeIn', 'easeOut', 'easeInOut'];
type SceneKey = 'component' | 'module' | 'events';

interface ListenerSpec extends TurboModule {
  addListener: (eventName: string) => void;
  removeListeners: (count: number) => void;
}

const nativeModule = TurboModuleRegistry.get<ListenerSpec>('AvoidSoftInput');

function DemoText({
  children,
  numberOfLines,
  style,
  testID,
}: {
  children: React.ReactNode;
  numberOfLines?: number;
  style?: object | object[];
  testID?: string;
}): React.JSX.Element {
  return (
    <Text allowFontScaling={false} numberOfLines={numberOfLines} style={style} testID={testID}>
      {children}
    </Text>
  );
}

function ActionButton({
  title,
  onPress,
  selected = false,
  compact = false,
  testID,
}: {
  title: string;
  onPress: () => void;
  selected?: boolean;
  compact?: boolean;
  testID?: string;
}): React.JSX.Element {
  return (
    <TouchableOpacity
      activeOpacity={0.76}
      onPress={onPress}
      style={[styles.button, selected && styles.buttonSelected, compact && styles.buttonCompact]}
      testID={testID}
    >
      <DemoText style={[styles.buttonText, selected && styles.buttonTextSelected]}>{title}</DemoText>
    </TouchableOpacity>
  );
}

function NumberStepper({
  label,
  value,
  onChange,
  step,
  testID,
}: {
  label: string;
  value: number;
  onChange: (value: number) => void;
  step: number;
  testID: string;
}): React.JSX.Element {
  return (
    <View style={styles.settingRow} testID={testID}>
      <View style={styles.settingLabel}>
        <DemoText style={styles.settingTitle}>{label}</DemoText>
        <DemoText style={styles.settingValue}>{value}</DemoText>
      </View>
      <View style={styles.stepper}>
        <ActionButton compact title="-" onPress={() => onChange(Math.max(0, value - step))} />
        <ActionButton compact title="+" onPress={() => onChange(value + step)} />
      </View>
    </View>
  );
}

function LogPanel({ title, lines }: { title: string; lines: string[] }): React.JSX.Element {
  return (
    <View style={styles.logBox} collapsable={false}>
      <DemoText style={styles.logTitle}>{title}</DemoText>
      <ScrollView style={styles.logScroll} nestedScrollEnabled>
        {lines.length === 0 ? (
          <DemoText style={styles.logEmpty}>等待输入框聚焦或按钮调用</DemoText>
        ) : (
          lines.map((line, i) => (
            <DemoText key={`${i}-${line}`} style={styles.logLine}>
              {line}
            </DemoText>
          ))
        )}
      </ScrollView>
    </View>
  );
}

function Field({
  testID,
  placeholder,
  value,
  onChangeText,
  numeric = false,
}: {
  testID: string;
  placeholder: string;
  value: string;
  onChangeText: (value: string) => void;
  numeric?: boolean;
}): React.JSX.Element {
  return (
    <TextInput
      allowFontScaling={false}
      keyboardType={numeric ? 'numeric' : 'default'}
      onChangeText={onChangeText}
      placeholder={placeholder}
      placeholderTextColor="#758195"
      style={styles.input}
      testID={testID}
      value={value}
    />
  );
}

export default function App(): React.JSX.Element {
  const platformOS = Platform.OS as string;
  const isHarmony = platformOS === 'harmony';
  const softInputState = useSoftInputState();

  const [scene, setScene] = React.useState<SceneKey>('component');
  const [moduleLog, setModuleLog] = React.useState<string[]>([]);
  const [componentLog, setComponentLog] = React.useState<string[]>([]);
  const [lastAction, setLastAction] = React.useState('等待操作');

  const [moduleEnabled, setModuleEnabled] = React.useState(true);
  const [moduleOffsetText, setModuleOffsetText] = React.useState('40');
  const [moduleShowDelayText, setModuleShowDelayText] = React.useState('0');
  const [moduleShowDurationText, setModuleShowDurationText] = React.useState('660');
  const [moduleHideDelayText, setModuleHideDelayText] = React.useState('0');
  const [moduleHideDurationText, setModuleHideDurationText] = React.useState('220');
  const [moduleEasingIdx, setModuleEasingIdx] = React.useState(0);

  const [viewEnabled, setViewEnabled] = React.useState(true);
  const [viewOffset, setViewOffset] = React.useState(24);
  const [viewEasingIdx, setViewEasingIdx] = React.useState(0);
  const [viewShowDelay, setViewShowDelay] = React.useState(0);
  const [viewShowDuration, setViewShowDuration] = React.useState(660);
  const [viewHideDelay, setViewHideDelay] = React.useState(0);
  const [viewHideDuration, setViewHideDuration] = React.useState(220);

  const [componentInput, setComponentInput] = React.useState('');
  const [moduleInput, setModuleInput] = React.useState('');
  const [eventsInput, setEventsInput] = React.useState('');

  const pushModuleLog = React.useCallback((line: string) => {
    setModuleLog((prev) => [`${new Date().toISOString().slice(11, 19)} ${line}`, ...prev].slice(0, 24));
  }, []);

  const pushComponentLog = React.useCallback((line: string) => {
    setComponentLog((prev) => [`${new Date().toISOString().slice(11, 19)} ${line}`, ...prev].slice(0, 24));
  }, []);

  React.useEffect(() => {
    const shown = AvoidSoftInput.onSoftInputShown(({ softInputHeight }) => {
      pushModuleLog(`device shown height(vp)=${softInputHeight}`);
    });
    const hidden = AvoidSoftInput.onSoftInputHidden(({ softInputHeight }) => {
      pushModuleLog(`device hidden height(vp)=${softInputHeight}`);
    });
    const heightChange = AvoidSoftInput.onSoftInputHeightChange(({ softInputHeight }) => {
      pushModuleLog(`device heightChange height(vp)=${softInputHeight}`);
    });
    const offsetChange = AvoidSoftInput.onSoftInputAppliedOffsetChange(({ appliedOffset }) => {
      pushModuleLog(`device appliedOffset(vp)=${appliedOffset}`);
    });

    return () => {
      shown.remove();
      hidden.remove();
      heightChange.remove();
      offsetChange.remove();
    };
  }, [pushModuleLog]);

  React.useEffect(() => {
    AvoidSoftInput.setEnabled(scene === 'module' && moduleEnabled);
    setLastAction(scene === 'module' ? `模块 setEnabled(${moduleEnabled})` : '当前由组件 props 控制避让');

    return () => {
      AvoidSoftInput.setEnabled(false);
    };
  }, [moduleEnabled, scene]);

  const callModuleNumberMethod = React.useCallback(
    (name: string, rawValue: string, call: (value: number) => void) => {
      const value = Number(rawValue) || 0;
      call(value);
      const line = `${name}(${value})`;
      pushModuleLog(line);
      setLastAction(line);
    },
    [pushModuleLog],
  );

  const switchModuleEasing = React.useCallback(() => {
    const next = (moduleEasingIdx + 1) % EASINGS.length;
    const easing = EASINGS[next] as SoftInputEasing;
    setModuleEasingIdx(next);
    AvoidSoftInput.setEasing(easing);
    pushModuleLog(`setEasing(${easing})`);
    setLastAction(`setEasing(${easing})`);
  }, [moduleEasingIdx, pushModuleLog]);

  const callAndroidOnlyMethods = React.useCallback(() => {
    AvoidSoftInput.setAdjustNothing();
    AvoidSoftInput.setAdjustPan();
    AvoidSoftInput.setAdjustResize();
    AvoidSoftInput.setAdjustUnspecified();
    AvoidSoftInput.setDefaultAppSoftInputMode();
    AvoidSoftInput.setShouldMimicIOSBehavior(true);
    const note = isHarmony
      ? 'Harmony:JS facade 直接返回,验证兼容入口无害'
      : 'Android:已调用 6 个窗口模式方法';
    pushModuleLog(note);
    setLastAction(note);
  }, [isHarmony, pushModuleLog]);

  const callListenerTemplate = React.useCallback(() => {
    nativeModule?.addListener('softInputShown');
    nativeModule?.removeListeners(1);
    const note = 'addListener/removeListeners 样板调用完成';
    pushModuleLog(note);
    setLastAction(note);
  }, [pushModuleLog]);

  return (
    <SafeAreaView style={styles.safeRoot}>
      <View style={styles.topSpacer} />
      <View style={styles.header}>
        <DemoText testID="app-title" style={styles.title} numberOfLines={1}>
          react-native-avoid-softinput
        </DemoText>
        <DemoText style={styles.subtitle}>HarmonyOS · Platform.OS={platformOS}</DemoText>
      </View>

      <View testID="hook-state" style={styles.statusStrip}>
        <DemoText style={styles.statusItem}>shown: {String(softInputState.isSoftInputShown)}</DemoText>
        <DemoText style={styles.statusItem}>键盘高度 (vp): {softInputState.softInputHeight}</DemoText>
        <DemoText style={styles.statusAction} numberOfLines={1}>
          {lastAction}
        </DemoText>
      </View>

      <View style={styles.tabs}>
        <ActionButton compact selected={scene === 'component'} testID="tab-component" title="组件" onPress={() => setScene('component')} />
        <ActionButton compact selected={scene === 'module'} testID="tab-module" title="模块" onPress={() => setScene('module')} />
        <ActionButton compact selected={scene === 'events'} testID="tab-events" title="事件" onPress={() => setScene('events')} />
      </View>

      {scene === 'component' ? (
        <AvoidSoftInputView
          avoidOffset={viewOffset}
          easing={EASINGS[viewEasingIdx]}
          enabled={viewEnabled}
          hideAnimationDelay={viewHideDelay}
          hideAnimationDuration={viewHideDuration}
          onSoftInputAppliedOffsetChange={(e) =>
            pushComponentLog(`view appliedOffset(vp)=${e.nativeEvent.appliedOffset}`)
          }
          onSoftInputHeightChange={(e) => pushComponentLog(`view heightChange(vp)=${e.nativeEvent.softInputHeight}`)}
          onSoftInputHidden={(e) => pushComponentLog(`view hidden height(vp)=${e.nativeEvent.softInputHeight}`)}
          onSoftInputShown={(e) => pushComponentLog(`view shown height(vp)=${e.nativeEvent.softInputHeight}`)}
          showAnimationDelay={viewShowDelay}
          showAnimationDuration={viewShowDuration}
          style={styles.scene}
          testID="avoid-view"
        >
          <ScrollView
            contentContainerStyle={styles.content}
            keyboardShouldPersistTaps="handled"
            nestedScrollEnabled
            showsVerticalScrollIndicator={false}
          >
            <View style={styles.sectionHeader}>
              <DemoText style={styles.sectionTitle}>组件避让验证</DemoText>
              <DemoText style={styles.sectionHint}>输入框在 AvoidSoftInputView 内部,聚焦后观察避让和组件事件</DemoText>
            </View>
            <Field
              onChangeText={setComponentInput}
              placeholder="聚焦验证组件避让"
              testID="component-input"
              value={componentInput}
            />
            <Field
              onChangeText={setComponentInput}
              placeholder="底部输入框:键盘弹起时不应被遮挡"
              testID="bottom-input"
              value={componentInput}
            />
            <View style={styles.switchRow}>
              <ActionButton selected={viewEnabled} title={`enabled=${String(viewEnabled)}`} onPress={() => setViewEnabled((v) => !v)} />
              <ActionButton
                title={`easing=${EASINGS[viewEasingIdx]}`}
                onPress={() => setViewEasingIdx((v) => (v + 1) % EASINGS.length)}
              />
            </View>
            <DemoText style={styles.groupTitle}>View 7 props</DemoText>
            <NumberStepper label="avoidOffset (vp)" onChange={setViewOffset} step={8} testID="view-avoid-offset" value={viewOffset} />
            <NumberStepper
              label="showAnimationDelay"
              onChange={setViewShowDelay}
              step={50}
              testID="view-show-delay"
              value={viewShowDelay}
            />
            <NumberStepper
              label="showAnimationDuration"
              onChange={setViewShowDuration}
              step={50}
              testID="view-show-duration"
              value={viewShowDuration}
            />
            <NumberStepper
              label="hideAnimationDelay"
              onChange={setViewHideDelay}
              step={50}
              testID="view-hide-delay"
              value={viewHideDelay}
            />
            <NumberStepper
              label="hideAnimationDuration"
              onChange={setViewHideDuration}
              step={50}
              testID="view-hide-duration"
              value={viewHideDuration}
            />
            <LogPanel lines={componentLog} title="组件事件" />
          </ScrollView>
        </AvoidSoftInputView>
      ) : null}

      {scene === 'module' ? (
        <View style={styles.scene} testID="module-scene">
          <ScrollView
            contentContainerStyle={styles.content}
            keyboardShouldPersistTaps="handled"
            nestedScrollEnabled
            showsVerticalScrollIndicator={false}
          >
            <View style={styles.sectionHeader}>
              <DemoText style={styles.sectionTitle}>AvoidSoftInput module</DemoText>
              <DemoText style={styles.sectionHint}>普通 View 根路径,不嵌套 AvoidSoftInputView</DemoText>
            </View>
            <View style={styles.switchRow}>
              <ActionButton
                selected={moduleEnabled}
                title={`setEnabled(${String(moduleEnabled)})`}
                onPress={() => setModuleEnabled((v) => !v)}
                testID="module-enabled"
              />
              <ActionButton title={`setEasing(${EASINGS[moduleEasingIdx]})`} onPress={switchModuleEasing} />
            </View>
            <View style={styles.formPair}>
              <Field
                numeric
                onChangeText={setModuleOffsetText}
                placeholder="offset"
                testID="input-avoid-offset"
                value={moduleOffsetText}
              />
              <ActionButton
                title="setAvoidOffset"
                onPress={() => callModuleNumberMethod('setAvoidOffset', moduleOffsetText, AvoidSoftInput.setAvoidOffset)}
              />
            </View>
            <View style={styles.formPair}>
              <Field
                numeric
                onChangeText={setModuleShowDelayText}
                placeholder="show delay"
                testID="input-show-delay"
                value={moduleShowDelayText}
              />
              <ActionButton
                title="setShowAnimationDelay"
                onPress={() =>
                  callModuleNumberMethod('setShowAnimationDelay', moduleShowDelayText, AvoidSoftInput.setShowAnimationDelay)
                }
              />
            </View>
            <View style={styles.formPair}>
              <Field
                numeric
                onChangeText={setModuleShowDurationText}
                placeholder="show duration"
                testID="input-show-duration"
                value={moduleShowDurationText}
              />
              <ActionButton
                title="setShowAnimationDuration"
                onPress={() =>
                  callModuleNumberMethod(
                    'setShowAnimationDuration',
                    moduleShowDurationText,
                    AvoidSoftInput.setShowAnimationDuration,
                  )
                }
              />
            </View>
            <View style={styles.formPair}>
              <Field
                numeric
                onChangeText={setModuleHideDelayText}
                placeholder="hide delay"
                testID="input-hide-delay"
                value={moduleHideDelayText}
              />
              <ActionButton
                title="setHideAnimationDelay"
                onPress={() =>
                  callModuleNumberMethod('setHideAnimationDelay', moduleHideDelayText, AvoidSoftInput.setHideAnimationDelay)
                }
              />
            </View>
            <View style={styles.formPair}>
              <Field
                numeric
                onChangeText={setModuleHideDurationText}
                placeholder="hide duration"
                testID="input-hide-duration"
                value={moduleHideDurationText}
              />
              <ActionButton
                title="setHideAnimationDuration"
                onPress={() =>
                  callModuleNumberMethod(
                    'setHideAnimationDuration',
                    moduleHideDurationText,
                    AvoidSoftInput.setHideAnimationDuration,
                  )
                }
              />
            </View>
            <View style={styles.switchRow}>
              <ActionButton title="Android 专属兼容入口" onPress={callAndroidOnlyMethods} testID="android-only-methods" />
              <ActionButton title="listener 样板" onPress={callListenerTemplate} testID="listener-template" />
            </View>
            <Field
              onChangeText={setModuleInput}
              placeholder="聚焦验证模块根路径避让"
              testID="module-input"
              value={moduleInput}
            />
            <Field
              onChangeText={setModuleInput}
              placeholder="底部输入框:模块路径验证"
              testID="module-bottom-input"
              value={moduleInput}
            />
            <LogPanel lines={moduleLog} title="模块 device 事件" />
          </ScrollView>
        </View>
      ) : null}

      {scene === 'events' ? (
        <View style={styles.scene} testID="events-scene">
          <ScrollView
            contentContainerStyle={styles.content}
            keyboardShouldPersistTaps="handled"
            nestedScrollEnabled
            showsVerticalScrollIndicator={false}
          >
            <View style={styles.sectionHeader}>
              <DemoText style={styles.sectionTitle}>状态与事件</DemoText>
              <DemoText style={styles.sectionHint}>useSoftInputState、4 个 device 事件、4 个组件事件</DemoText>
            </View>
            <Field onChangeText={setEventsInput} placeholder="聚焦后观察状态和事件日志" testID="event-input" value={eventsInput} />
            <LogPanel lines={moduleLog} title="device event log" />
            <LogPanel lines={componentLog} title="component event log" />
          </ScrollView>
        </View>
      ) : null}
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  safeRoot: {
    flex: 1,
    backgroundColor: '#f7f8fb',
  },
  topSpacer: {
    height: 20,
  },
  header: {
    paddingHorizontal: 14,
    paddingBottom: 6,
  },
  title: {
    color: '#111827',
    fontSize: 14,
    fontWeight: '800',
    lineHeight: 18,
  },
  subtitle: {
    color: '#526070',
    fontSize: 11,
    lineHeight: 15,
    marginTop: 1,
  },
  statusStrip: {
    alignItems: 'center',
    backgroundColor: '#eef2f7',
    borderBottomColor: '#d9e0ea',
    borderBottomWidth: 1,
    borderTopColor: '#d9e0ea',
    borderTopWidth: 1,
    flexDirection: 'row',
    gap: 6,
    minHeight: 30,
    paddingHorizontal: 10,
  },
  statusItem: {
    color: '#1f2937',
    fontSize: 10,
    fontWeight: '700',
  },
  statusAction: {
    color: '#42526b',
    flex: 1,
    fontSize: 10,
    textAlign: 'right',
  },
  tabs: {
    backgroundColor: '#ffffff',
    borderBottomColor: '#dfe5ee',
    borderBottomWidth: 1,
    flexDirection: 'row',
    gap: 6,
    paddingHorizontal: 10,
    paddingVertical: 7,
  },
  scene: {
    flex: 1,
  },
  content: {
    gap: 8,
    padding: 10,
    paddingBottom: 52,
  },
  sectionHeader: {
    gap: 3,
    marginBottom: 2,
  },
  sectionTitle: {
    color: '#111827',
    fontSize: 14,
    fontWeight: '800',
    lineHeight: 19,
  },
  sectionHint: {
    color: '#526070',
    fontSize: 10,
    lineHeight: 14,
  },
  groupTitle: {
    color: '#364152',
    fontSize: 11,
    fontWeight: '800',
    lineHeight: 15,
    marginTop: 2,
  },
  switchRow: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    gap: 8,
  },
  formPair: {
    alignItems: 'center',
    flexDirection: 'row',
    gap: 8,
  },
  settingRow: {
    alignItems: 'center',
    backgroundColor: '#ffffff',
    borderColor: '#dfe5ee',
    borderRadius: 6,
    borderWidth: 1,
    flexDirection: 'row',
    minHeight: 38,
    paddingHorizontal: 8,
    paddingVertical: 4,
  },
  settingLabel: {
    flex: 1,
    minWidth: 0,
  },
  settingTitle: {
    color: '#263141',
    fontSize: 11,
    fontWeight: '700',
    lineHeight: 15,
  },
  settingValue: {
    color: '#526070',
    fontSize: 10,
    lineHeight: 14,
    marginTop: 1,
  },
  stepper: {
    flexDirection: 'row',
    gap: 6,
  },
  input: {
    backgroundColor: '#ffffff',
    borderColor: '#cfd8e4',
    borderRadius: 6,
    borderWidth: 1,
    color: '#111827',
    flex: 1,
    fontSize: 12,
    minHeight: 36,
    paddingHorizontal: 10,
  },
  button: {
    alignItems: 'center',
    backgroundColor: '#ffffff',
    borderColor: '#b8c4d4',
    borderRadius: 6,
    borderWidth: 1,
    justifyContent: 'center',
    minHeight: 34,
    minWidth: 78,
    paddingHorizontal: 10,
  },
  buttonCompact: {
    minHeight: 30,
    minWidth: 42,
    paddingHorizontal: 8,
  },
  buttonSelected: {
    backgroundColor: '#174ea6',
    borderColor: '#174ea6',
  },
  buttonText: {
    color: '#1f2937',
    fontSize: 11,
    fontWeight: '700',
    lineHeight: 14,
    textAlign: 'center',
  },
  buttonTextSelected: {
    color: '#ffffff',
  },
  logBox: {
    backgroundColor: '#101828',
    borderRadius: 6,
    minHeight: 158,
    overflow: 'hidden',
  },
  logTitle: {
    backgroundColor: '#1d2939',
    color: '#ffffff',
    fontSize: 11,
    fontWeight: '800',
    lineHeight: 15,
    paddingHorizontal: 8,
    paddingVertical: 6,
  },
  logScroll: {
    maxHeight: 220,
    paddingHorizontal: 8,
    paddingVertical: 6,
  },
  logEmpty: {
    color: '#98a2b3',
    fontSize: 10,
    lineHeight: 15,
  },
  logLine: {
    color: '#d0d5dd',
    fontSize: 10,
    lineHeight: 15,
  },
});