/**
 * 会话列表行：React.memo + 稳定比较，减少 Tab 切换等场景下的无关重渲染。
 * onPress 引用不参与比较，请配合父组件 ref + 按 id 查最新会话使用。
 */

import React, { memo, useEffect, useMemo, useRef, useState } from 'react';
import { Animated, StyleSheet, TouchableOpacity, View } from 'react-native';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import { spacing, shadows, useAppColors, type AppColors } from '../../../theme';
import {
  ConversationResponse,
  extractTextFromSegments,
  extractTextFromSegmentsAsync,
  MessageSegment,
} from '../../../types/dto';
import { authService } from '../../../services';
import { getUserCache } from '../../../services/database';
import { Avatar, Text } from '../../../components/common';

const AnimatedTouchable = Animated.createAnimatedComponent(TouchableOpacity);
const MAX_CONVERSATION_NAME_LENGTH = 10;

const truncateDisplayName = (name: string, maxLength: number = MAX_CONVERSATION_NAME_LENGTH): string => {
  if (!name) return '';
  if (name.length <= maxLength) return name;
  return `${name.slice(0, maxLength)}...`;
};

/**
 * 异步消息预览（与会话行同文件，仅供列表使用）
 */
const AsyncMessagePreview: React.FC<{
  segments?: MessageSegment[];
  status?: string;
  isGroupChat?: boolean;
  senderName?: string;
}> = ({ segments, status, isGroupChat, senderName }) => {
  const [displayText, setDisplayText] = useState<string>('');
  const isMountedRef = useRef(true);

  useEffect(() => {
    isMountedRef.current = true;

    const loadPreview = async () => {
      if (status === 'recalled') {
        if (isMountedRef.current) {
          setDisplayText('消息已撤回');
        }
        return;
      }

      const initialText = extractTextFromSegments(segments);
      if (isMountedRef.current) {
        setDisplayText(initialText);
      }

      const hasAtWithoutNickname = segments?.some(
        (s) => s.type === 'at' && s.data.user_id !== 'all' && !s.data.nickname
      );

      if (hasAtWithoutNickname) {
        try {
          const asyncText = await extractTextFromSegmentsAsync(
            segments,
            getUserCache,
            authService.getUserById.bind(authService)
          );
          if (isMountedRef.current && asyncText !== initialText) {
            setDisplayText(asyncText);
          }
        } catch (error) {
          console.warn('[AsyncMessagePreview] 获取用户名失败:', error);
        }
      }
    };

    loadPreview();

    return () => {
      isMountedRef.current = false;
    };
  }, [segments, status]);

  if (!displayText) return null;

  if (isGroupChat && senderName) {
    return (
      <>
        {senderName}: {displayText}
      </>
    );
  }

  return <>{displayText}</>;
};

export interface ConversationListRowProps {
  item: ConversationResponse;
  index: number;
  scale: Animated.Value | number;
  isSelected: boolean;
  onPress: () => void;
  formatTime: (dateString: string) => string;
  systemChannelId: string;
}

function conversationVisualSignature(item: ConversationResponse): string {
  const lm = item.last_message;
  const lmSender = lm?.sender;
  const lmPart = lm
    ? [
        lm.id,
        String(lm.seq),
        lm.status,
        String(lm.segments?.length ?? 0),
        extractTextFromSegments(lm.segments),
        lmSender?.nickname ?? '',
        lmSender?.username ?? '',
      ].join('|')
    : '';
  const g = item.group;
  const gPart = g ? [String(g.id), g.name, g.avatar ?? ''].join('|') : '';
  const p0 = item.participants?.[0];
  const pPart = p0 ? [p0.id, p0.nickname ?? '', p0.avatar ?? ''].join('|') : '';
  return [
    String(item.id),
    item.type,
    item.is_pinned ? '1' : '0',
    String(item.unread_count),
    item.last_message_at,
    item.updated_at,
    String(item.last_seq),
    String(item.member_count ?? ''),
    lmPart,
    gPart,
    pPart,
  ].join('\u001f');
}

function areConversationRowEqual(
  prev: ConversationListRowProps,
  next: ConversationListRowProps
): boolean {
  if (prev.isSelected !== next.isSelected) return false;
  if (prev.index !== next.index) return false;
  if (prev.scale !== next.scale) return false;
  if (prev.systemChannelId !== next.systemChannelId) return false;
  if (conversationVisualSignature(prev.item) !== conversationVisualSignature(next.item)) return false;
  // onPress、formatTime 故意不比：父组件用 ref 保证行为最新
  return true;
}

function createConversationRowStyles(colors: AppColors) {
  return StyleSheet.create({
    conversationItem: {
      flexDirection: 'row',
      alignItems: 'center',
      paddingHorizontal: spacing.md,
      paddingVertical: 14,
      backgroundColor: colors.background.paper,
      marginHorizontal: spacing.md,
      marginTop: spacing.sm,
      borderRadius: 12,
      ...shadows.sm,
    },
    conversationItemSelected: {
      backgroundColor: colors.primary.light + '20',
      borderColor: colors.primary.main,
      borderWidth: 1,
    },
    avatarContainer: {
      position: 'relative',
    },
    systemAvatar: {
      width: 50,
      height: 50,
      borderRadius: 12,
      alignItems: 'center',
      justifyContent: 'center',
      backgroundColor: colors.primary.main,
    },
    conversationContent: {
      flex: 1,
      marginLeft: spacing.md,
    },
    conversationHeader: {
      flexDirection: 'row',
      justifyContent: 'space-between',
      alignItems: 'center',
      marginBottom: 4,
    },
    nameRow: {
      flexDirection: 'row',
      alignItems: 'center',
    },
    officialBadge: {
      backgroundColor: colors.primary.main,
      borderRadius: 4,
      paddingHorizontal: 6,
      paddingVertical: 2,
      marginRight: spacing.xs,
    },
    officialBadgeText: {
      color: colors.primary.contrast,
      fontSize: 10,
      fontWeight: '600',
    },
    userName: {
      fontWeight: '600',
      color: colors.text.primary,
      fontSize: 16,
    },
    groupIcon: {
      marginRight: 4,
    },
    memberCount: {
      fontSize: 12,
      color: colors.text.secondary,
      marginLeft: 2,
    },
    pinnedIcon: {
      marginLeft: 6,
    },
    groupAvatar: {
      width: 50,
      height: 50,
    },
    groupAvatarPlaceholder: {
      width: 50,
      height: 50,
      borderRadius: 12,
      backgroundColor: colors.primary.main,
      alignItems: 'center',
      justifyContent: 'center',
    },
    timeText: {
      color: colors.text.secondary,
      fontSize: 12,
    },
    messageRow: {
      flexDirection: 'row',
      alignItems: 'center',
    },
    messageText: {
      flex: 1,
      color: colors.text.secondary,
      fontSize: 14,
    },
    unreadMessageText: {
      color: colors.text.primary,
      fontWeight: '500',
    },
    unreadBadge: {
      minWidth: 20,
      height: 20,
      borderRadius: 10,
      backgroundColor: colors.primary.main,
      alignItems: 'center',
      justifyContent: 'center',
      marginLeft: spacing.sm,
      paddingHorizontal: 6,
    },
    unreadBadgeText: {
      color: colors.primary.contrast,
      fontSize: 12,
      fontWeight: '600',
    },
  });
}

const ConversationListRowInner: React.FC<ConversationListRowProps> = ({
  item,
  scale,
  isSelected,
  onPress,
  formatTime,
  systemChannelId,
}) => {
  const colors = useAppColors();
  const styles = useMemo(() => createConversationRowStyles(colors), [colors]);
  const isSystemChannel = item.id === systemChannelId;
  const isGroupChat = !!(item.type === 'group' && item.group);

  let displayNameRaw: string;
  let displayName: string;
  let displayAvatar: string | null = null;

  if (isSystemChannel) {
    displayNameRaw = '系统通知';
  } else if (isGroupChat && item.group) {
    displayNameRaw = item.group.name || '群聊';
    displayAvatar = item.group.avatar && item.group.avatar.trim() !== '' ? item.group.avatar : null;
  } else {
    displayNameRaw = item.participants?.[0]?.nickname || '未知用户';
    displayAvatar = item.participants?.[0]?.avatar || null;
  }
  displayName = truncateDisplayName(displayNameRaw);

  const getSenderName = (): string | undefined => {
    if (isGroupChat && item.last_message?.sender) {
      return item.last_message.sender.nickname || item.last_message.sender.username;
    }
    return undefined;
  };

  return (
    <AnimatedTouchable
      style={[
        styles.conversationItem,
        isSelected && styles.conversationItemSelected,
        { transform: [{ scale }] },
      ]}
      onPress={onPress}
      activeOpacity={0.7}
    >
      <View style={styles.avatarContainer}>
        {isSystemChannel ? (
          <View style={styles.systemAvatar}>
            <MaterialCommunityIcons name="bell-ring" size={24} color={colors.primary.contrast} />
          </View>
        ) : isGroupChat ? (
          <View style={styles.groupAvatar}>
            {displayAvatar ? (
              <Avatar source={displayAvatar} size={50} name={displayName} />
            ) : (
              <View style={styles.groupAvatarPlaceholder}>
                <MaterialCommunityIcons name="account-group" size={28} color={colors.primary.contrast} />
              </View>
            )}
          </View>
        ) : (
          <Avatar source={displayAvatar} size={50} name={displayName} />
        )}
      </View>

      <View style={styles.conversationContent}>
        <View style={styles.conversationHeader}>
          <View style={styles.nameRow}>
            {isSystemChannel && (
              <View style={styles.officialBadge}>
                <Text style={styles.officialBadgeText}>官方</Text>
              </View>
            )}
            {isGroupChat && (
              <MaterialCommunityIcons
                name="account-group"
                size={16}
                color={colors.primary.main}
                style={styles.groupIcon}
              />
            )}
            <Text style={styles.userName}>{displayName}</Text>
            {item.is_pinned && !isSystemChannel && (
              <MaterialCommunityIcons name="pin" size={14} color={colors.warning.main} style={styles.pinnedIcon} />
            )}
            {isGroupChat && item.member_count !== undefined && (
              <Text style={styles.memberCount}>({item.member_count})</Text>
            )}
          </View>
          <Text style={styles.timeText}>{formatTime(item.last_message_at || item.updated_at)}</Text>
        </View>
        <View style={styles.messageRow}>
          <Text
            style={item.unread_count > 0 ? [styles.messageText, styles.unreadMessageText] : styles.messageText}
            numberOfLines={1}
          >
            {!item.last_message ? (
              '暂无消息'
            ) : (
              <AsyncMessagePreview
                segments={item.last_message?.segments}
                status={item.last_message?.status}
                isGroupChat={isGroupChat}
                senderName={getSenderName()}
              />
            )}
          </Text>
          {item.unread_count > 0 && (
            <View style={styles.unreadBadge}>
              <Text style={styles.unreadBadgeText}>
                {item.unread_count > 99 ? '99+' : item.unread_count}
              </Text>
            </View>
          )}
        </View>
      </View>
    </AnimatedTouchable>
  );
};

ConversationListRowInner.displayName = 'ConversationListRow';

export const ConversationListRow = memo(ConversationListRowInner, areConversationRowEqual);
