/**
 * PostCard 主组件
 * 帖子卡片组件（新实现）
 *
 * @example
 * // 新 API 使用方式
 * <PostCard
 *   post={post}
 *   onAction={(action) => handleAction(post, action)}
 *   variant="list"
 *   features="full"
 * />
 */

import React, { useMemo, useState, memo, useEffect } from 'react';
import { View, TouchableOpacity, StyleSheet, Alert, TextStyle } from 'react-native';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import { PostCardProps, PostCardAction } from './types';
import { ImageGridItem, SmartImage } from '../../common';
import Text from '../../common/Text';
import Avatar from '../../common/Avatar';
import { colors, spacing, borderRadius, fontSizes } from '../../../theme';
import { getPreviewImageUrl } from '../../../utils/imageHelper';
import PostImages from './components/PostImages';
import { useResponsive } from '../../../hooks/useResponsive';
import { formatPostCreatedAtString } from '../../../core/entities/Post';

/** 列表相对时间：独立定时刷新，避免外层 PostCard.memo 挡住「分钟前」更新 */
const PostCardRelativeTime: React.FC<{ createdAt?: string | null; style?: TextStyle | TextStyle[] }> = ({
  createdAt,
  style: timeStyle,
}) => {
  const [label, setLabel] = useState(() => formatPostCreatedAtString(createdAt));

  useEffect(() => {
    setLabel(formatPostCreatedAtString(createdAt));
    const tick = () => setLabel(formatPostCreatedAtString(createdAt));
    const id = setInterval(tick, 60_000);
    return () => clearInterval(id);
  }, [createdAt]);

  return (
    <Text style={timeStyle} numberOfLines={1}>
      {label}
    </Text>
  );
};

function imagesSignature(
  images: PostCardProps['post']['images'] | undefined
): string {
  if (!images?.length) return '';
  return images.map((i) => i.id).join('\u001f');
}

function authorSignature(author: PostCardProps['post']['author']): string {
  if (!author) return '';
  return [author.id, author.nickname ?? '', author.avatar ?? ''].join('\u001f');
}

function topCommentSignature(tc: PostCardProps['post']['top_comment']): string {
  if (!tc) return '';
  return [tc.id, tc.content ?? '', tc.author?.id ?? ''].join('\u001f');
}

function channelSignature(ch: PostCardProps['post']['channel']): string {
  if (!ch) return '';
  return [ch.id, ch.name ?? ''].join('\u001f');
}

function featuresComparable(f: PostCardProps['features']): string {
  if (f == null) return '';
  if (typeof f === 'string') return f;
  return JSON.stringify(f);
}

/**
 * 自定义比较：忽略 onAction 引用（父组件应用 postId + ref 解析最新 post，避免 Tab 切换时全列表因回调重建而重绘）。
 * index 未参与 UI，不比较以免列表重排时多余更新。
 */
function arePostCardPropsEqual(prev: PostCardProps, next: PostCardProps): boolean {
  if (prev.variant !== next.variant) return false;
  if (prev.isPostAuthor !== next.isPostAuthor) return false;
  if (prev.isAuthor !== next.isAuthor) return false;
  if (prev.style !== next.style) return false;
  if (featuresComparable(prev.features) !== featuresComparable(next.features)) return false;

  const a = prev.post;
  const b = next.post;
  if (a === b) return true;

  if (a.id !== b.id) return false;
  if (a.title !== b.title) return false;
  if (a.content !== b.content) return false;
  if ((a.likes_count ?? 0) !== (b.likes_count ?? 0)) return false;
  if ((a.comments_count ?? 0) !== (b.comments_count ?? 0)) return false;
  if ((a.favorites_count ?? 0) !== (b.favorites_count ?? 0)) return false;
  if ((a.shares_count ?? 0) !== (b.shares_count ?? 0)) return false;
  if ((a.views_count ?? 0) !== (b.views_count ?? 0)) return false;
  if (!!a.is_pinned !== !!b.is_pinned) return false;
  if (!!a.is_locked !== !!b.is_locked) return false;
  if (!!a.is_vote !== !!b.is_vote) return false;
  if (a.created_at !== b.created_at) return false;
  if (a.updated_at !== b.updated_at) return false;
  if (a.content_edited_at !== b.content_edited_at) return false;
  if (!!a.is_liked !== !!b.is_liked) return false;
  if (!!a.is_favorited !== !!b.is_favorited) return false;
  if (authorSignature(a.author) !== authorSignature(b.author)) return false;
  if (imagesSignature(a.images) !== imagesSignature(b.images)) return false;
  if (topCommentSignature(a.top_comment) !== topCommentSignature(b.top_comment)) return false;
  if (channelSignature(a.channel) !== channelSignature(b.channel)) return false;

  return true;
}

/**
 * PostCard 主组件
 * 仅支持新 API
 */
const PostCardInner: React.FC<PostCardProps> = (normalizedProps) => {
  const {
    post,
    onAction,
    variant = 'list',
    features,
    isPostAuthor = false,
    isAuthor = false,
    index,
    style,
  } = normalizedProps;

  const [isExpanded, setIsExpanded] = useState(false);
  const [isDeleting, setIsDeleting] = useState(false);

  const isCompact =
    features === 'compact' ||
    (typeof features === 'object' && features?.showContent === false);

  const emit = (action: PostCardAction) => {
    onAction(action);
  };

  const handleImagePress = (images: ImageGridItem[], imageIndex: number) => {
    emit({ type: 'imagePress', payload: { images, imageIndex } });
  };

  const showGrid = variant === 'grid';
  const author = post.author;
  const rawContent = post.content ?? '';
  const { isDesktop, isTablet, isWideScreen, isLandscape } = useResponsive();

  const handleCardPress = () => emit({ type: 'press' });
  const handleUserPress = () => emit({ type: 'userPress' });
  const handleLike = () => emit({ type: post.is_liked ? 'unlike' : 'like' });
  const handleComment = () => emit({ type: 'comment' });
  const handleBookmark = () => emit({ type: post.is_favorited ? 'unbookmark' : 'bookmark' });
  const handleShare = () => emit({ type: 'share' });
  const handleDelete = () => {
    if (isDeleting) return;
    Alert.alert(
      '删除帖子',
      '确定要删除这篇帖子吗？删除后将无法恢复。',
      [
        { text: '取消', style: 'cancel' },
        {
          text: '删除',
          style: 'destructive',
          onPress: async () => {
            setIsDeleting(true);
            try {
              emit({ type: 'delete' });
            } finally {
              setIsDeleting(false);
            }
          },
        },
      ],
    );
  };

  const images: ImageGridItem[] = Array.isArray(post.images)
    ? post.images.map((img) => ({
        id: img.id,
        url: img.url,
        thumbnail_url: img.thumbnail_url,
        preview_url: img.preview_url,
        preview_url_large: img.preview_url_large,
        width: img.width,
        height: img.height,
      }))
    : [];

  const formatNumber = (num: number): string => {
    if (num >= 10000) return `${(num / 10000).toFixed(1)}w`;
    if (num >= 1000) return `${(num / 1000).toFixed(1)}k`;
    return String(num);
  };

  const getResponsiveMaxLength = () => {
    if (isWideScreen) return 300;
    if (isDesktop) return 250;
    if (isTablet) return 200;
    return 100;
  };

  const contentNumberOfLines = useMemo(() => {
    if (isWideScreen) return 8;
    if (isDesktop) return 6;
    if (isTablet) return 5;
    return 3;
  }, [isWideScreen, isDesktop, isTablet]);

  const getTruncatedContent = (value: string): string => {
    const maxLength = getResponsiveMaxLength();
    if (value.length <= maxLength || isExpanded) return value;
    return `${value.substring(0, maxLength)}...`;
  };

  const shouldTruncate = !showGrid && !isCompact && rawContent.length > getResponsiveMaxLength();
  const content = useMemo(
    () => (showGrid || isCompact ? rawContent : getTruncatedContent(rawContent)),
    [rawContent, showGrid, isCompact, isExpanded, isWideScreen, isDesktop, isTablet]
  );

  const renderImages = () => {
    if (images.length === 0) return null;

    if (showGrid) {
      const cover = images[0];
      const coverUrl = getPreviewImageUrl(cover as any, 'grid');
      return (
        <TouchableOpacity activeOpacity={0.9} onPress={() => handleImagePress(images, 0)}>
          <SmartImage
            source={{ uri: coverUrl || cover.url || '' }}
            style={styles.gridCover}
            resizeMode="cover"
            usePreview={true}
          />
        </TouchableOpacity>
      );
    }

    return (
      <PostImages
        images={post.images || []}
        displayMode="list"
        onImagePress={handleImagePress}
      />
    );
  };

  const renderTopComment = () => {
    if (showGrid || !post.top_comment) return null;
    return (
      <TouchableOpacity style={styles.topCommentBox} activeOpacity={0.85} onPress={handleComment}>
        <Text style={styles.topCommentAuthor} numberOfLines={1}>
          {post.top_comment.author?.nickname || '匿名用户'}:
        </Text>
        <Text style={styles.topCommentText} numberOfLines={1}>
          {post.top_comment.content}
        </Text>
      </TouchableOpacity>
    );
  };

  const renderGridCard = () => {
    const cover = images[0];
    const hasImage = !!cover;
    const coverUrl = hasImage ? getPreviewImageUrl(cover as any, 'grid') : '';
    const contentPreview = rawContent
      .replace(/[#*_~`\[\]()]/g, '')
      .replace(/\n+/g, ' ')
      .trim();

    return (
      <TouchableOpacity
        activeOpacity={0.9}
        onPress={handleCardPress}
        style={[styles.gridRootCard, style]}
      >
        {hasImage ? (
          <TouchableOpacity activeOpacity={0.9} onPress={() => handleImagePress(images, 0)}>
            <SmartImage
              source={{ uri: coverUrl || cover.url || '' }}
              style={styles.gridCover}
              resizeMode="cover"
              usePreview={true}
            />
          </TouchableOpacity>
        ) : (
          <View style={styles.gridNoImagePreview}>
            <Text style={styles.gridNoImageText} numberOfLines={6}>
              {contentPreview}
            </Text>
          </View>
        )}

        {post.is_vote && (
          <View style={styles.gridVoteTag}>
            <MaterialCommunityIcons name="vote" size={11} color={colors.primary.contrast} />
            <Text style={styles.gridVoteTagText}>投票</Text>
          </View>
        )}

        {!!post.title && (
          <Text style={styles.gridTitleMain} numberOfLines={hasImage ? 2 : 3}>
            {post.title}
          </Text>
        )}

        {!!post.channel?.name && (
          <View style={styles.gridChannelRow}>
            <MaterialCommunityIcons name="tag-outline" size={12} color={colors.text.hint} />
            <Text style={styles.gridChannelText} numberOfLines={1}>
              {post.channel.name}
            </Text>
          </View>
        )}

        <View style={styles.gridFooter}>
          <TouchableOpacity onPress={handleUserPress} style={styles.gridUserArea}>
            <Avatar source={author?.avatar} size={20} name={author?.nickname || '匿名用户'} />
            <Text style={styles.gridUsername} numberOfLines={1}>{author?.nickname || '匿名用户'}</Text>
          </TouchableOpacity>
          <View style={styles.gridLikeArea}>
            <MaterialCommunityIcons name="heart-outline" size={14} color={colors.text.secondary} />
            <Text style={styles.gridLikeCount}>{formatNumber(post.likes_count || 0)}</Text>
          </View>
        </View>
      </TouchableOpacity>
    );
  };

  return (
    showGrid ? renderGridCard() : (
    <TouchableOpacity
      activeOpacity={0.9}
      onPress={handleCardPress}
      style={[styles.card, style]}
    >
      <View style={styles.header}>
        <TouchableOpacity onPress={handleUserPress} activeOpacity={0.8} style={styles.authorWrap}>
          <Avatar source={author?.avatar} size={showGrid ? 22 : 36} name={author?.nickname || '匿名用户'} />
          <View style={styles.authorMeta}>
            <Text style={styles.authorName} numberOfLines={1}>{author?.nickname || '匿名用户'}</Text>
            {!showGrid && (
              <View style={styles.metaRow}>
                <PostCardRelativeTime createdAt={post.created_at} style={styles.timeText} />
                {!!post.channel?.name && (
                  <View style={styles.channelTag}>
                    <MaterialCommunityIcons name="tag-outline" size={11} color={colors.primary.main} />
                    <Text style={styles.channelTagText} numberOfLines={1}>
                      {post.channel.name}
                    </Text>
                  </View>
                )}
                {post.is_pinned && (
                  <View style={styles.pinnedTag}>
                    <MaterialCommunityIcons name="pin" size={10} color={colors.warning.main} />
                    <Text style={styles.pinnedText}>置顶</Text>
                  </View>
                )}
                {isAuthor && <Text style={styles.badgeText}>楼主</Text>}
              </View>
            )}
          </View>
        </TouchableOpacity>
        {isPostAuthor && (
          <TouchableOpacity onPress={handleDelete} hitSlop={8} style={styles.deleteButton} disabled={isDeleting}>
            <MaterialCommunityIcons
              name={isDeleting ? 'loading' : 'delete-outline'}
              size={isDesktop ? 20 : 18}
              color={colors.text.hint}
            />
          </TouchableOpacity>
        )}
      </View>

      {!!post.title && (
        <Text style={styles.title} numberOfLines={isCompact ? 2 : undefined}>
          {post.title}
        </Text>
      )}

      {!isCompact && !!content && (
        <>
          <Text
            style={styles.content}
            numberOfLines={isExpanded ? undefined : contentNumberOfLines}
          >
            {content}
          </Text>
          {shouldTruncate && (
            <TouchableOpacity onPress={() => setIsExpanded((prev) => !prev)} style={styles.expandBtn}>
              <Text style={styles.expandText}>{isExpanded ? '收起' : '展开全文'}</Text>
            </TouchableOpacity>
          )}
        </>
      )}

      {renderImages()}
      {renderTopComment()}

      <View style={styles.actions}>
        <View style={styles.viewsWrap}>
          <MaterialCommunityIcons name="eye-outline" size={16} color={colors.text.hint} />
          <Text style={styles.viewsText}>{post.views_count || 0}</Text>
        </View>
        <View style={styles.actionButtons}>
          <TouchableOpacity style={styles.actionBtn} onPress={handleLike}>
            <MaterialCommunityIcons
              name={post.is_liked ? 'heart' : 'heart-outline'}
              size={18}
              color={post.is_liked ? colors.error.main : colors.text.secondary}
            />
            <Text style={post.is_liked ? styles.activeActionTextMerged : styles.actionText}>
              {post.likes_count > 0 ? formatNumber(post.likes_count) : '赞'}
            </Text>
          </TouchableOpacity>
          <TouchableOpacity style={styles.actionBtn} onPress={handleComment}>
            <MaterialCommunityIcons name="comment-outline" size={18} color={colors.text.secondary} />
            <Text style={styles.actionText}>{post.comments_count > 0 ? formatNumber(post.comments_count) : '评论'}</Text>
          </TouchableOpacity>
          <TouchableOpacity style={styles.actionBtn} onPress={handleShare}>
            <MaterialCommunityIcons name="share-outline" size={18} color={colors.text.secondary} />
          </TouchableOpacity>
          <TouchableOpacity style={styles.actionBtn} onPress={handleBookmark}>
            <MaterialCommunityIcons
              name={post.is_favorited ? 'bookmark' : 'bookmark-outline'}
              size={18}
              color={post.is_favorited ? colors.warning.main : colors.text.secondary}
            />
          </TouchableOpacity>
        </View>
      </View>
    </TouchableOpacity>
    )
  );
};

PostCardInner.displayName = 'PostCard';

const PostCard = memo(PostCardInner, arePostCardPropsEqual);

const styles = StyleSheet.create({
  card: {
    backgroundColor: colors.background.paper,
    borderRadius: borderRadius.lg,
    padding: spacing.md,
    borderWidth: StyleSheet.hairlineWidth,
    borderColor: colors.divider,
  },
  header: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    marginBottom: spacing.sm,
  },
  authorWrap: {
    flexDirection: 'row',
    alignItems: 'center',
    flex: 1,
    minWidth: 0,
  },
  authorMeta: {
    marginLeft: spacing.sm,
    flex: 1,
    minWidth: 0,
  },
  authorName: {
    color: colors.text.primary,
    fontWeight: '600',
    fontSize: fontSizes.md,
  },
  timeText: {
    color: colors.text.hint,
    fontSize: fontSizes.xs,
    marginTop: 2,
  },
  metaRow: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 6,
    marginTop: 2,
    flexWrap: 'wrap',
  },
  channelTag: {
    flexDirection: 'row',
    alignItems: 'center',
    maxWidth: 140,
    paddingHorizontal: 6,
    paddingVertical: 2,
    borderRadius: borderRadius.sm,
    backgroundColor: `${colors.primary.main}12`,
    gap: 4,
  },
  channelTagText: {
    fontSize: fontSizes.xs,
    color: colors.primary.main,
    fontWeight: '600',
    flexShrink: 1,
  },
  pinnedTag: {
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: `${colors.warning.light}22`,
    borderRadius: borderRadius.sm,
    paddingHorizontal: 4,
    paddingVertical: 1,
    gap: 2,
  },
  pinnedText: {
    color: colors.warning.main,
    fontSize: fontSizes.xs,
  },
  badgeText: {
    color: colors.primary.main,
    fontSize: fontSizes.xs,
    fontWeight: '600',
  },
  deleteButton: {
    padding: spacing.xs,
    marginLeft: spacing.sm,
  },
  title: {
    color: colors.text.primary,
    fontSize: fontSizes.lg,
    fontWeight: '600',
    marginBottom: spacing.xs,
  },
  content: {
    color: colors.text.secondary,
    fontSize: fontSizes.md,
    marginBottom: spacing.xs,
    lineHeight: fontSizes.md * 1.45,
  },
  expandBtn: {
    marginBottom: spacing.sm,
  },
  expandText: {
    color: colors.primary.main,
    fontSize: fontSizes.sm,
  },
  topCommentBox: {
    backgroundColor: colors.background.default,
    borderRadius: borderRadius.sm,
    paddingHorizontal: spacing.sm,
    paddingVertical: spacing.xs,
    marginBottom: spacing.sm,
    flexDirection: 'row',
    alignItems: 'center',
  },
  topCommentAuthor: {
    color: colors.text.secondary,
    fontSize: fontSizes.sm,
    fontWeight: '600',
    marginRight: 4,
  },
  topCommentText: {
    color: colors.text.secondary,
    fontSize: fontSizes.sm,
    flex: 1,
  },
  gridCover: {
    width: '100%',
    aspectRatio: 0.78,
    backgroundColor: colors.background.default,
  },
  actions: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
  },
  viewsWrap: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  viewsText: {
    color: colors.text.hint,
    fontSize: fontSizes.sm,
    marginLeft: 4,
  },
  actionButtons: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  actionBtn: {
    flexDirection: 'row',
    alignItems: 'center',
    marginLeft: spacing.md,
  },
  actionText: {
    color: colors.text.secondary,
    fontSize: fontSizes.sm,
    marginLeft: 4,
  },
  activeActionText: {
    color: colors.error.main,
  },
  activeActionTextMerged: {
    color: colors.error.main,
    fontSize: fontSizes.sm,
    marginLeft: 4,
  },
  gridRootCard: {
    backgroundColor: colors.background.paper,
    borderRadius: borderRadius.lg,
    overflow: 'hidden',
    borderWidth: StyleSheet.hairlineWidth,
    borderColor: colors.divider,
  },
  gridNoImagePreview: {
    backgroundColor: colors.background.default,
    margin: 6,
    borderRadius: borderRadius.md,
    minHeight: 120,
    padding: 8,
  },
  gridNoImageText: {
    color: colors.text.secondary,
    fontSize: fontSizes.sm,
    lineHeight: 20,
  },
  gridVoteTag: {
    position: 'absolute',
    top: 8,
    right: 8,
    backgroundColor: `${colors.primary.main}CC`,
    borderRadius: borderRadius.full,
    paddingHorizontal: 8,
    paddingVertical: 4,
    flexDirection: 'row',
    alignItems: 'center',
    gap: 4,
  },
  gridVoteTagText: {
    color: colors.primary.contrast,
    fontSize: 10,
    fontWeight: '600',
  },
  gridTitleMain: {
    color: colors.text.primary,
    fontSize: fontSizes.md,
    lineHeight: 20,
    paddingHorizontal: 8,
    paddingTop: 8,
    minHeight: 44,
  },
  gridChannelRow: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 4,
    paddingHorizontal: 8,
    paddingTop: 4,
    paddingBottom: 2,
  },
  gridChannelText: {
    fontSize: fontSizes.xs,
    color: colors.text.secondary,
    fontWeight: '600',
    flex: 1,
    minWidth: 0,
  },
  gridFooter: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    paddingHorizontal: 8,
    paddingVertical: 10,
  },
  gridUserArea: {
    flexDirection: 'row',
    alignItems: 'center',
    flex: 1,
    minWidth: 0,
  },
  gridUsername: {
    color: colors.text.secondary,
    fontSize: fontSizes.sm,
    marginLeft: 6,
    flex: 1,
  },
  gridLikeArea: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  gridLikeCount: {
    color: colors.text.secondary,
    fontSize: fontSizes.sm,
    marginLeft: 4,
  },
});

export default PostCard;