import { Image } from 'expo-image';
import { useLocalSearchParams } from 'expo-router';
import { Mic, Pause, Play, PlusCircle, Type, X } from 'lucide-react-native';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import type {
  NativeSyntheticEvent,
  TextInputContentSizeChangeEventData,
} from 'react-native';
import {
  Alert,
  Animated,
  FlatList,
  InteractionManager,
  Keyboard,
  KeyboardAvoidingView,
  Platform,
  Pressable,
  StyleSheet,
  Text as RNText,
  TextInput,
  View,
} from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useTranslation } from 'react-i18next';

import { Icon } from '@/components/ui/icon';
import { Text } from '@/components/ui/text';
import { ScreenHeader } from '@/components/screen-header';
import { useThemeColors } from '@/hooks/use-theme-colors';
import { useMessages, useRealtimeSession } from '@/features/conversation/hooks';
import type { MessageItem } from '@/features/conversation/types';
import { isVoiceMessage } from '@/features/conversation/types';
import { usePlayer } from '@/features/voice/hooks/use-player';
import { useRecorder } from '@/features/voice/hooks/use-recorder';

// Life-Echo chat colors (from HTML reference)
const CHAT_COLORS = {
  background: '#F8F9FA',
  surface: '#fbf8fd',
  surfaceContainer: '#f5f3f7',
  primary: '#8177A6',
  primaryBorder: '#49416c',
  onPrimary: '#ffffff',
  onSurface: '#1b1b1f',
  onSurfaceVariant: '#8D8C90',
  outline: '#cac4cf',
  secondaryContainer: '#edd4ff',
  primaryFixed: '#e7deff',
  errorRed: '#ba1a1a',
};

/** 后端用 [SPLIT] 分隔多条消息，需按块渲染为多个气泡 */
const SPLIT_DELIMITER = '[SPLIT]';

/** 聊天输入框：单行内容高度与最多约 4 行（与 lineHeight 对齐） */
const CHAT_INPUT_LINE_H = 22;
const CHAT_INPUT_MAX_H = CHAT_INPUT_LINE_H * 4;

function splitContent(content: string): string[] {
  return content
    .split(SPLIT_DELIMITER)
    .map((s) => s.trim())
    .filter((s) => s.length > 0);
}

const AGENT_AVATAR =
  'https://lh3.googleusercontent.com/aida-public/AB6AXuC2cLdqTitOjFBnGTNsoJGh45K9zvV89vxB0EEHh0DT-YlbiOVyTuSmni5SO2eDOMC1HrW8cuhj29_KJJJFMV8aEPLHCwQgGA006Q9EfoDtEHP4GnzB4SEnT8bjCk6lQwjgh2Qp5dvq8oQTU5aQnKXtqOTAIIw1I3GWYlKimGa7Zqw4lnax84XRRGeYp6wj_1B9WsXuDvY7mNHIN7y_Tw0-TbRK1MGMHgd_nMNEqoqUCX6VAaDF2BjLB7BQnzIql8_8mw0TPaw1R3wO';
const USER_AVATAR =
  'https://lh3.googleusercontent.com/aida-public/AB6AXuAMCjDBVhsUUXRAz9AGYejbTGoEYhzyiggYt_QIFqHCc3odRcBPNRhsE2Klg7gOeOV9V_qOy5qPqjU0GmpfgjGAWKGXZCizwRVz96N0n1IFMx4JH7QwV81zQsaVvCdJct_uABUBEawhncvQcbl0jUt_EUlNgzB-gIgUS_oLlT1TtRb8S5s7sAqwLRdGBa61yxL1X1iSWSFIn5N-WPIDs_vpCgS47q9SQjkT1q7VKvPzHzTiGF1bwVvjB7Bl2JgtaIUj6rkwlLbPG6xb';

type InputMode = 'text' | 'voice';

/** 展平消息列表：assistant 消息按 [SPLIT] 拆成多条，每条一个 listKey */
function flattenMessagesForList(
  messages: MessageItem[],
): (MessageItem & { listKey: string })[] {
  const result: (MessageItem & { listKey: string })[] = [];
  for (const msg of messages) {
    if (msg.senderType === 'user') {
      result.push({ ...msg, listKey: msg.id });
    } else {
      const parts = splitContent(msg.content);
      if (parts.length > 1) {
        parts.forEach((part, i) => {
          result.push({
            ...msg,
            content: part,
            listKey: `${msg.id}_part_${i}`,
          });
        });
      } else {
        result.push({ ...msg, listKey: msg.id });
      }
    }
  }
  return result;
}

function MessageBubble({
  item,
  agentName,
  meLabel,
  currentPlaybackUri,
  playbackIsPlaying,
  onPlayVoiceExclusive,
  onPausePlayback,
}: {
  item: MessageItem;
  agentName: string;
  meLabel: string;
  currentPlaybackUri: string | null;
  playbackIsPlaying: boolean;
  onPlayVoiceExclusive: (uri: string) => void;
  onPausePlayback: () => void;
}) {
  const isUser = item.senderType === 'user';
  const isVoice = isVoiceMessage(item);

  return (
    <View style={[styles.messageRow, isUser && styles.messageRowReverse]}>
      <View
        style={[
          styles.avatarWrapper,
          isUser ? styles.avatarWrapperUser : styles.avatarWrapperAgent,
        ]}
      >
        <Image
          source={{ uri: isUser ? USER_AVATAR : AGENT_AVATAR }}
          style={styles.avatarImage}
          alt={isUser ? meLabel : agentName}
        />
      </View>
      <View style={[styles.bubbleColumn, isUser && styles.bubbleColumnEnd]}>
        <Text
          style={[
            styles.nickname,
            isUser ? styles.nicknameUser : styles.nicknameAgent,
          ]}
        >
          {isUser ? meLabel : agentName}
        </Text>
        {isVoice ? (
          <View
            style={[
              styles.bubble,
              isUser ? styles.bubbleUser : styles.bubbleAgent,
            ]}
          >
            <VoiceMessageBubble
              durationSeconds={item.durationSeconds ?? 0}
              audioUri={item.audioUri}
              isUser={isUser}
              isPlaying={
                !!item.audioUri &&
                playbackIsPlaying &&
                currentPlaybackUri === item.audioUri
              }
              onPlayPress={() => {
                if (!item.audioUri) return;
                if (playbackIsPlaying && currentPlaybackUri === item.audioUri) {
                  onPausePlayback();
                } else {
                  onPlayVoiceExclusive(item.audioUri);
                }
              }}
            />
          </View>
        ) : (
          <View
            style={[
              styles.bubble,
              isUser ? styles.bubbleUser : styles.bubbleAgent,
            ]}
          >
            <Text
              selectable
              style={[
                styles.bubbleText,
                isUser ? styles.bubbleTextUser : styles.bubbleTextAgent,
              ]}
            >
              {item.content}
            </Text>
          </View>
        )}
      </View>
    </View>
  );
}

function StreamingBubbles({
  streamingText,
  isComplete,
  agentName,
}: {
  streamingText: string;
  isComplete: boolean;
  agentName: string;
}) {
  const parts = splitContent(streamingText);
  const completedParts = parts.length > 1 ? parts.slice(0, -1) : [];
  const streamingPart =
    parts.length > 1 ? parts[parts.length - 1]! : (parts[0] ?? streamingText);

  return (
    <View>
      {completedParts.map((part, i) => (
        <View
          key={`streaming_complete_${i}`}
          style={[styles.messageRow, styles.streamingRow]}
        >
          <View style={[styles.avatarWrapper, styles.avatarWrapperAgent]}>
            <Image
              source={{ uri: AGENT_AVATAR }}
              style={styles.avatarImage}
              alt={agentName}
            />
          </View>
          <View style={[styles.bubbleColumn]}>
            <Text style={[styles.nickname, styles.nicknameAgent]}>
              {agentName}
            </Text>
            <View style={[styles.bubble, styles.bubbleAgent]}>
              <Text
                selectable
                style={[styles.bubbleText, styles.bubbleTextAgent]}
              >
                {part}
              </Text>
            </View>
          </View>
        </View>
      ))}
      <View style={[styles.messageRow, styles.streamingRow]}>
        <View style={[styles.avatarWrapper, styles.avatarWrapperAgent]}>
          <Image
            source={{ uri: AGENT_AVATAR }}
            style={styles.avatarImage}
            alt={agentName}
          />
        </View>
        <View style={[styles.bubbleColumn]}>
          <Text style={[styles.nickname, styles.nicknameAgent]}>
            {agentName}
          </Text>
          <View style={[styles.bubble, styles.bubbleAgent]}>
            <Text
              selectable
              style={[styles.bubbleText, styles.bubbleTextAgent]}
            >
              {streamingPart}
              {!isComplete && '▌'}
            </Text>
          </View>
        </View>
      </View>
    </View>
  );
}

function formatRecordingDuration(seconds: number): string {
  const s = Math.max(0, Math.floor(seconds));
  const mins = Math.floor(s / 60);
  const secs = s % 60;
  return `${mins}:${secs.toString().padStart(2, '0')}`;
}

function VoiceMessageBubble({
  durationSeconds,
  audioUri,
  isUser,
  isPlaying,
  onPlayPress,
}: {
  durationSeconds: number;
  audioUri?: string;
  isUser: boolean;
  isPlaying: boolean;
  onPlayPress: () => void;
}) {
  const handlePlayPause = useCallback(() => {
    onPlayPress();
  }, [onPlayPress]);

  return (
    <View
      style={[
        styles.voiceMessageBubble,
        isUser ? styles.voiceMessageBubbleUser : styles.voiceMessageBubbleAgent,
      ]}
    >
      <Pressable
        onPress={handlePlayPause}
        style={({ pressed }) => [
          styles.voicePlayButton,
          pressed && { opacity: 0.7 },
        ]}
        disabled={!audioUri}
        accessibilityLabel={isPlaying ? 'Pause' : 'Play'}
        accessibilityRole="button"
      >
        <Icon
          as={isPlaying ? Pause : Play}
          size={24}
          color={isUser ? CHAT_COLORS.onSurface : CHAT_COLORS.onPrimary}
        />
      </Pressable>
      <Text
        style={[
          styles.voiceDurationText,
          isUser ? styles.voiceDurationTextUser : styles.voiceDurationTextAgent,
        ]}
      >
        {formatRecordingDuration(durationSeconds)}
      </Text>
    </View>
  );
}

function VoiceRecordButton({
  isRecording,
  recordingDuration,
  onPress,
  tapToStartLabel,
  tapToEndLabel,
  enabled,
}: {
  isRecording: boolean;
  recordingDuration: number;
  onPress: () => void;
  tapToStartLabel: string;
  tapToEndLabel: string;
  enabled: boolean;
}) {
  const pulseAnim = useRef(new Animated.Value(0.85)).current;

  useEffect(() => {
    if (!isRecording) return;
    const anim = Animated.loop(
      Animated.sequence([
        Animated.timing(pulseAnim, {
          toValue: 1.15,
          duration: 450,
          useNativeDriver: true,
        }),
        Animated.timing(pulseAnim, {
          toValue: 0.85,
          duration: 450,
          useNativeDriver: true,
        }),
      ]),
    );
    anim.start();
    return () => anim.stop();
  }, [isRecording, pulseAnim]);

  return (
    <Pressable
      onPress={onPress}
      style={[
        styles.voiceRecordCenter,
        isRecording && styles.voiceRecordCenterRecording,
      ]}
      disabled={!enabled}
    >
      {isRecording ? (
        <View style={styles.voiceRecordLabelCenterWrap}>
          <Text
            style={[
              styles.voiceRecordLabel,
              styles.voiceRecordLabelCenter,
              styles.voiceRecordLabelRecording,
              !enabled && styles.voiceRecordLabelDisabled,
            ]}
            numberOfLines={1}
          >
            {tapToEndLabel}
          </Text>
        </View>
      ) : (
        <Text
          style={[
            styles.voiceRecordLabel,
            !enabled && styles.voiceRecordLabelDisabled,
            styles.voiceRecordLabelCenter,
          ]}
          numberOfLines={1}
        >
          {tapToStartLabel}
        </Text>
      )}
      {isRecording && (
        <View style={styles.voiceRecordPill}>
          <Animated.View
            style={[
              styles.voiceRecordPulseDot,
              { transform: [{ scale: pulseAnim }] },
            ]}
          />
          <View style={styles.voiceRecordDurationWrap}>
            <RNText
              style={[
                styles.voiceRecordDuration,
                Platform.OS === 'android' && styles.voiceRecordDurationAndroid,
              ]}
              {...(Platform.OS === 'android' && { includeFontPadding: false })}
            >
              {formatRecordingDuration(recordingDuration)}
            </RNText>
          </View>
        </View>
      )}
    </Pressable>
  );
}

function ChatInputBar({
  value,
  onChangeText,
  onSend,
  inputMode,
  onInputModeToggle,
  onAddPress,
  onStartRecording,
  onStopRecording,
  onCancelRecording,
  isRecording,
  recordingDuration,
  placeholder,
  placeholderVoice,
  addMoreLabel,
  sendLabel,
  switchToVoiceLabel,
  switchToTextLabel,
  tapToStartLabel,
  tapToEndLabel,
  cancelRecordingLabel,
  disabled,
  textInputKey = 0,
}: {
  value: string;
  onChangeText: (v: string) => void;
  onSend: () => void;
  inputMode: InputMode;
  onInputModeToggle: () => void;
  onAddPress: () => void;
  onStartRecording: () => void;
  onStopRecording: () => void;
  onCancelRecording: () => void;
  isRecording: boolean;
  recordingDuration: number;
  placeholder: string;
  placeholderVoice: string;
  addMoreLabel: string;
  sendLabel: string;
  switchToVoiceLabel: string;
  switchToTextLabel: string;
  tapToStartLabel: string;
  tapToEndLabel: string;
  cancelRecordingLabel: string;
  disabled?: boolean;
  /** 发送后递增，强制重建 TextInput，避免多行高度卡在 4 行 */
  textInputKey?: number;
}) {
  const colors = useThemeColors();
  const [textHeight, setTextHeight] = useState(CHAT_INPUT_LINE_H);
  /** 空串时立即单行高度，避免仅依赖 state 时发送后仍沿用 4 行测量值 */
  const inputDisplayHeight = value === '' ? CHAT_INPUT_LINE_H : textHeight;

  useEffect(() => {
    if (value === '') {
      setTextHeight(CHAT_INPUT_LINE_H);
    }
  }, [value]);

  const onInputContentSizeChange = useCallback(
    (e: NativeSyntheticEvent<TextInputContentSizeChangeEventData>) => {
      const h = e.nativeEvent.contentSize.height;
      const next = Math.min(Math.max(h, CHAT_INPUT_LINE_H), CHAT_INPUT_MAX_H);
      setTextHeight(next);
    },
    [],
  );

  const hasText = value.trim().length > 0;
  const showSend = inputMode === 'text' && hasText;

  // 右侧按钮：文字模式有内容->发送；语音模式录音中->取消；否则->更多
  const trailingAction = showSend
    ? 'send'
    : inputMode === 'voice' && isRecording
      ? 'cancel'
      : 'add';

  return (
    <View style={styles.inputBar}>
      {/* 左侧：麦克风/键盘切换 */}
      <Pressable
        onPress={onInputModeToggle}
        style={({ pressed }) => [
          styles.iconButton,
          pressed && styles.iconButtonPressed,
        ]}
        disabled={disabled && !isRecording}
        accessibilityLabel={
          inputMode === 'text' ? switchToVoiceLabel : switchToTextLabel
        }
        accessibilityRole="button"
      >
        <Icon
          as={inputMode === 'text' ? Mic : Type}
          size={22}
          color={
            disabled && !isRecording
              ? 'rgba(141, 140, 144, 0.56)'
              : CHAT_COLORS.onSurfaceVariant
          }
        />
      </Pressable>
      {/* 中间：文字输入 或 语音录制按钮 */}
      {inputMode === 'text' ? (
        <View style={styles.inputCenter}>
          <TextInput
            key={`chat-input-${textInputKey}`}
            value={value}
            onChangeText={onChangeText}
            placeholder={placeholder}
            placeholderTextColor={CHAT_COLORS.onSurfaceVariant}
            style={[styles.textInput, { height: inputDisplayHeight }]}
            multiline
            scrollEnabled
            textAlignVertical="top"
            maxLength={2000}
            editable={!disabled}
            onContentSizeChange={onInputContentSizeChange}
            onSubmitEditing={onSend}
            returnKeyType="send"
          />
        </View>
      ) : (
        <View style={styles.inputCenterFlex}>
          <VoiceRecordButton
            isRecording={isRecording}
            recordingDuration={recordingDuration}
            onPress={isRecording ? onStopRecording : onStartRecording}
            tapToStartLabel={tapToStartLabel}
            tapToEndLabel={tapToEndLabel}
            enabled={!disabled}
          />
        </View>
      )}
      {/* 右侧：发送 / 取消录音 / 更多 */}
      {trailingAction === 'send' ? (
        <Pressable
          onPress={onSend}
          style={({ pressed }) => [
            styles.sendButton,
            { backgroundColor: colors.primary },
            disabled && styles.sendButtonDisabled,
            pressed && !disabled && styles.sendButtonPressed,
          ]}
          disabled={disabled}
          accessibilityLabel={sendLabel}
          accessibilityRole="button"
        >
          <Text
            style={[styles.sendButtonText, { color: CHAT_COLORS.onSurface }]}
          >
            {sendLabel}
          </Text>
        </Pressable>
      ) : trailingAction === 'cancel' ? (
        <Pressable
          onPress={onCancelRecording}
          style={({ pressed }) => [
            styles.iconButton,
            pressed && styles.iconButtonPressed,
          ]}
          accessibilityLabel={cancelRecordingLabel}
          accessibilityRole="button"
        >
          <Icon as={X} size={22} color={CHAT_COLORS.errorRed} />
        </Pressable>
      ) : (
        <Pressable
          onPress={onAddPress}
          style={({ pressed }) => [
            styles.iconButton,
            pressed && styles.iconButtonPressed,
          ]}
          disabled={disabled && !isRecording}
          accessibilityLabel={addMoreLabel}
          accessibilityRole="button"
        >
          <Icon
            as={PlusCircle}
            size={22}
            color={
              disabled && !isRecording
                ? 'rgba(141, 140, 144, 0.56)'
                : CHAT_COLORS.onSurfaceVariant
            }
          />
        </Pressable>
      )}
    </View>
  );
}

export default function ConversationScreen() {
  const { id } = useLocalSearchParams<{ id: string }>();
  const insets = useSafeAreaInsets();
  const { t } = useTranslation('conversation');
  const { t: tApp } = useTranslation('app');
  const { data: messages } = useMessages(id);
  const {
    enqueue,
    enqueueExclusive,
    stop,
    status: playerStatus,
    currentSource,
  } = usePlayer();

  const handleTtsSegment = useCallback(
    (p: { audioBase64?: string; audioUrl?: string }) => {
      if (p.audioBase64) {
        void enqueue({
          uri: `data:audio/mp3;base64,${p.audioBase64}`,
          label: 'TTS',
        });
      } else if (p.audioUrl) {
        void enqueue({ uri: p.audioUrl, label: 'TTS' });
      }
    },
    [enqueue],
  );

  const handlePlayVoiceExclusive = useCallback(
    (uri: string) => {
      void enqueueExclusive({ uri, label: 'voice' });
    },
    [enqueueExclusive],
  );

  const handlePausePlayback = useCallback(() => {
    void stop();
  }, [stop]);

  const { connectionState, streamingMessage, sendText, sendVoiceMessage } =
    useRealtimeSession({
      conversationId: id ?? '',
      enabled: !!id,
      onTtsSegment: handleTtsSegment,
    });

  const handleRecordingComplete = useCallback(
    (uri: string, durationMs: number) => {
      void sendVoiceMessage(uri, durationMs);
    },
    [sendVoiceMessage],
  );

  const {
    status: recorderStatus,
    durationMs: recordingDurationMs,
    start: startRecording,
    stop: stopRecording,
    cancel: cancelRecording,
  } = useRecorder(handleRecordingComplete);

  const [input, setInput] = useState('');
  const [inputResetKey, setInputResetKey] = useState(0);
  const [inputMode, setInputMode] = useState<InputMode>('text');
  const [isKeyboardVisible, setIsKeyboardVisible] = useState(false);
  const [keyboardHeight, setKeyboardHeight] = useState(0);
  const listRef = useRef<FlatList>(null);

  useEffect(() => {
    const onShow = (e: { endCoordinates: { height: number } }) => {
      setIsKeyboardVisible(true);
      setKeyboardHeight(e.endCoordinates.height);
      InteractionManager.runAfterInteractions(() => {
        listRef.current?.scrollToEnd({ animated: true });
      });
    };
    const onHide = () => {
      setIsKeyboardVisible(false);
      setKeyboardHeight(0);
    };
    // iOS：Will* 与系统动画同步；KeyboardAvoidingView 在 iOS 上易与 safe area 叠出缝（见 RN #52626）
    const showEvt =
      Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow';
    const hideEvt =
      Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide';
    const subShow = Keyboard.addListener(showEvt, onShow);
    const subHide = Keyboard.addListener(hideEvt, onHide);
    return () => {
      subShow.remove();
      subHide.remove();
    };
  }, [insets.bottom]);

  const flattenedData = flattenMessagesForList(messages ?? []);

  const isRecording = recorderStatus === 'recording';
  const recordingDuration = Math.floor(recordingDurationMs / 1000);

  const handleStartRecording = useCallback(async () => {
    const ok = await startRecording();
    if (!ok) {
      Alert.alert(t('recordingPermissionDenied'));
    }
  }, [startRecording, t]);

  const handleSend = () => {
    const text = input.trim();
    if (!text) return;
    sendText(text);
    setInput('');
    setInputResetKey((k) => k + 1);
  };

  const connectionLabel =
    connectionState === 'connected'
      ? t('connectionConnected')
      : connectionState === 'connecting'
        ? t('connectionConnecting')
        : t('connectionDisconnected');

  /** iOS：用键盘高度直接顶起根布局，替代 KAV（避免与 safe area 叠出缝，见 RN #52626） */
  const keyboardLift =
    Platform.OS === 'ios' && inputMode === 'text' && isKeyboardVisible
      ? keyboardHeight
      : 0;
  const androidKavOn =
    Platform.OS === 'android' && inputMode === 'text' && isKeyboardVisible;

  const composerZeroBottomInset = isKeyboardVisible && inputMode === 'text';

  const screen = (
    <View style={styles.column}>
      <ScreenHeader
        variant="chat"
        title={
          <View style={styles.headerTitleBlock}>
            <Text style={styles.headerTitle}>{tApp('name')}</Text>
            <View
              style={[
                styles.statusBadge,
                connectionState === 'connected' && styles.statusBadgeConnected,
              ]}
            >
              <Text
                style={[
                  styles.statusBadgeText,
                  connectionState === 'connected' &&
                    styles.statusBadgeTextConnected,
                ]}
              >
                {connectionLabel}
              </Text>
            </View>
          </View>
        }
        backAccessibilityLabel={t('chatTitle')}
      />

      {/* Message list - flex 1, takes remaining space */}
      <FlatList
        ref={listRef}
        style={styles.list}
        contentContainerStyle={styles.listContent}
        data={flattenedData}
        keyboardShouldPersistTaps="handled"
        keyboardDismissMode="on-drag"
        keyExtractor={(item) => item.listKey}
        renderItem={({ item }) => (
          <MessageBubble
            item={item}
            agentName={t('agentName')}
            meLabel={t('me')}
            currentPlaybackUri={currentSource}
            playbackIsPlaying={playerStatus === 'playing'}
            onPlayVoiceExclusive={handlePlayVoiceExclusive}
            onPausePlayback={handlePausePlayback}
          />
        )}
        onContentSizeChange={() =>
          InteractionManager.runAfterInteractions(() => {
            listRef.current?.scrollToEnd({ animated: true });
          })
        }
        ListFooterComponent={
          streamingMessage ? (
            <StreamingBubbles
              streamingText={streamingMessage.text}
              isComplete={streamingMessage.isComplete}
              agentName={t('agentName')}
            />
          ) : null
        }
      />

      {/* WeChat-style input bar - 贴在底部，非浮空 */}
      <View
        style={[
          styles.inputBarWrapper,
          {
            paddingBottom: composerZeroBottomInset ? 0 : insets.bottom,
          },
        ]}
      >
        <ChatInputBar
          value={input}
          onChangeText={setInput}
          onSend={handleSend}
          textInputKey={inputResetKey}
          inputMode={inputMode}
          onInputModeToggle={() => {
            setInputMode((m) => {
              if (m === 'text') {
                Keyboard.dismiss();
              }
              return m === 'text' ? 'voice' : 'text';
            });
          }}
          onAddPress={() => {}}
          onStartRecording={handleStartRecording}
          onStopRecording={() => void stopRecording()}
          onCancelRecording={() => void cancelRecording()}
          isRecording={isRecording}
          recordingDuration={recordingDuration}
          placeholder={t('inputPlaceholder')}
          placeholderVoice={t('inputPlaceholderVoice')}
          addMoreLabel={t('addMore')}
          sendLabel={t('send')}
          switchToVoiceLabel={t('switchToVoice')}
          switchToTextLabel={t('switchToText')}
          tapToStartLabel={t('tapToStartRecording')}
          tapToEndLabel={t('tapToEndRecording')}
          cancelRecordingLabel={t('cancelRecording')}
          disabled={connectionState !== 'connected'}
        />
      </View>
    </View>
  );

  if (Platform.OS === 'ios') {
    return (
      <View style={[styles.container, { paddingBottom: keyboardLift }]}>
        {screen}
      </View>
    );
  }

  return (
    <KeyboardAvoidingView
      style={styles.container}
      behavior={androidKavOn ? 'height' : undefined}
    >
      {screen}
    </KeyboardAvoidingView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: CHAT_COLORS.background,
  },
  column: {
    flex: 1,
    flexDirection: 'column',
  },
  headerTitleBlock: {
    flex: 1,
    flexDirection: 'row',
    alignItems: 'center',
    gap: 10,
  },
  headerTitle: {
    fontSize: 24,
    fontWeight: '700',
    color: CHAT_COLORS.primary,
    letterSpacing: -0.5,
  },
  statusBadge: {
    paddingHorizontal: 8,
    paddingVertical: 2,
    borderRadius: 4,
    backgroundColor: 'rgba(141, 140, 144, 0.2)',
    borderWidth: 1,
    borderColor: 'rgba(141, 140, 144, 0.3)',
  },
  statusBadgeConnected: {
    backgroundColor: 'rgba(34, 197, 94, 0.15)',
    borderColor: 'rgba(34, 197, 94, 0.3)',
  },
  statusBadgeText: {
    fontSize: 12,
    fontFamily: 'monospace',
    color: CHAT_COLORS.onSurfaceVariant,
  },
  statusBadgeTextConnected: {
    color: '#16a34a',
  },
  list: {
    flex: 1,
  },
  listContent: {
    flexGrow: 1,
    paddingHorizontal: 12,
    paddingTop: 16,
    paddingBottom: 12,
  },
  messageRow: {
    flexDirection: 'row',
    alignItems: 'flex-start',
    gap: 10,
    marginBottom: 16,
    overflow: 'visible',
  },
  messageRowReverse: {
    flexDirection: 'row-reverse',
  },
  streamingRow: {
    marginBottom: 0,
  },
  avatarWrapper: {
    width: 40,
    height: 40,
    flexShrink: 0,
    borderWidth: 2,
    overflow: 'hidden',
  },
  avatarWrapperAgent: {
    backgroundColor: CHAT_COLORS.secondaryContainer,
    borderColor: CHAT_COLORS.primary,
  },
  avatarWrapperUser: {
    backgroundColor: CHAT_COLORS.primaryFixed,
    borderColor: CHAT_COLORS.onSurfaceVariant,
  },
  avatarImage: {
    width: '100%',
    height: '100%',
  },
  bubbleColumn: {
    maxWidth: '80%',
    alignSelf: 'flex-start',
  },
  bubbleColumnEnd: {
    alignItems: 'flex-end',
    alignSelf: 'flex-end',
  },
  nickname: {
    fontSize: 16,
    fontWeight: '700',
    marginBottom: 2,
  },
  nicknameAgent: {
    color: CHAT_COLORS.primary,
  },
  nicknameUser: {
    color: CHAT_COLORS.onSurfaceVariant,
  },
  bubble: {
    padding: 12,
    borderWidth: 2,
    shadowOffset: { width: 4, height: 4 },
    shadowOpacity: 1,
    shadowRadius: 0,
  },
  bubbleAgent: {
    backgroundColor: CHAT_COLORS.primary,
    borderColor: CHAT_COLORS.primaryBorder,
    shadowColor: CHAT_COLORS.primaryBorder,
  },
  bubbleUser: {
    backgroundColor: '#ffffff',
    borderColor: CHAT_COLORS.onSurfaceVariant,
    shadowColor: CHAT_COLORS.outline,
  },
  bubbleText: {
    fontSize: 22,
    lineHeight: 34,
    fontWeight: '400',
  },
  bubbleTextAgent: {
    color: CHAT_COLORS.onPrimary,
  },
  bubbleTextUser: {
    color: CHAT_COLORS.onSurface,
  },
  voiceMessageBubble: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 12,
    paddingVertical: 4,
  },
  voiceMessageBubbleUser: {},
  voiceMessageBubbleAgent: {},
  voicePlayButton: {
    width: 44,
    height: 44,
    borderRadius: 22,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'rgba(255,255,255,0.2)',
  },
  voiceDurationText: {
    fontSize: 18,
    fontWeight: '500',
  },
  voiceDurationTextUser: {
    color: CHAT_COLORS.onSurface,
  },
  voiceDurationTextAgent: {
    color: CHAT_COLORS.onPrimary,
  },
  inputBarWrapper: {
    backgroundColor: CHAT_COLORS.surface,
    borderTopLeftRadius: 24,
    borderTopRightRadius: 24,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: -4 },
    shadowOpacity: 0.08,
    shadowRadius: 12,
    elevation: 8,
  },
  inputBar: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 10,
    paddingHorizontal: 14,
    paddingVertical: 12,
  },
  iconButton: {
    width: 44,
    height: 44,
    borderRadius: 22,
    alignItems: 'center',
    justifyContent: 'center',
  },
  iconButtonPressed: {
    opacity: 0.7,
  },
  inputCenter: {
    flex: 1,
    minHeight: 48,
    borderRadius: 16,
    backgroundColor: 'rgba(141, 140, 144, 0.14)',
    paddingHorizontal: 16,
    paddingVertical: 11,
    justifyContent: 'flex-start',
  },
  inputCenterFlex: {
    flex: 1,
    minHeight: 48,
  },
  voiceRecordCenter: {
    flex: 1,
    minHeight: 48,
    borderRadius: 16,
    backgroundColor: 'rgba(141, 140, 144, 0.14)',
    paddingHorizontal: 16,
    paddingVertical: 11,
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
  },
  voiceRecordCenterRecording: {
    backgroundColor: 'rgba(141, 140, 144, 0.20)',
  },
  voiceRecordLabel: {
    fontSize: 16,
    fontWeight: '500',
    color: 'rgba(27, 27, 31, 0.72)',
    flex: 1,
  },
  voiceRecordLabelCenter: {
    textAlign: 'center',
  },
  voiceRecordLabelCenterWrap: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  voiceRecordLabelRecording: {
    color: 'rgba(27, 27, 31, 0.92)',
  },
  voiceRecordLabelDisabled: {
    color: 'rgba(141, 140, 144, 0.68)',
  },
  voiceRecordPill: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 6,
    backgroundColor: 'rgba(255, 255, 255, 0.8)',
    borderRadius: 999,
    paddingHorizontal: 10,
    paddingVertical: 5,
  },
  voiceRecordPulseDot: {
    width: 7,
    height: 7,
    borderRadius: 3.5,
    backgroundColor: CHAT_COLORS.errorRed,
  },
  voiceRecordDurationWrap: {
    width: 32,
    alignItems: 'center',
    justifyContent: 'center',
  },
  voiceRecordDuration: {
    fontSize: 12,
    lineHeight: 12,
    color: 'rgba(27, 27, 31, 0.86)',
    textAlign: 'center',
  },
  voiceRecordDurationAndroid: {
    textAlignVertical: 'center',
  } as const,
  textInput: {
    fontSize: 16,
    lineHeight: CHAT_INPUT_LINE_H,
    color: CHAT_COLORS.onSurface,
    padding: 0,
    maxHeight: CHAT_INPUT_MAX_H,
    width: '100%',
  },
  sendButton: {
    height: 44,
    paddingHorizontal: 16,
    paddingVertical: 11,
    borderRadius: 22,
    alignItems: 'center',
    justifyContent: 'center',
  },
  sendButtonPressed: {
    opacity: 0.9,
  },
  sendButtonDisabled: {
    opacity: 0.45,
  },
  sendButtonText: {
    fontSize: 16,
    fontWeight: '500',
  },
});
