/**
 * Author wall — timeline of every post by a single author, newest first.
 *
 * Route: /(app)/feed/author/[pub]
 *
 * Entry points:
 *   - Profile screen "View posts" button.
 *   - Tapping the author name/avatar inside a PostCard.
 *
 * Backend: GET /feed/author/{pub}?limit=N[&before=ts]
 *   — chain-authoritative, returns FeedPostItem[] ordered newest-first.
 *
 * Pagination: infinite-scroll via onEndReached → appends the next page
 * anchored on the oldest timestamp we've seen. Safe to over-fetch because
 * the relay caps `limit`.
 */
import React, { useCallback, useEffect, useRef, useState } from 'react';
import {
  View, Text, FlatList, RefreshControl, ActivityIndicator, Pressable,
} from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { router, useLocalSearchParams } from 'expo-router';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

import { Header } from '@/components/Header';
import { IconButton } from '@/components/IconButton';
import { Avatar } from '@/components/Avatar';
import { PostCard, PostSeparator } from '@/components/feed/PostCard';
import { useStore } from '@/lib/store';
import { fetchAuthorPosts, fetchStats, type FeedPostItem } from '@/lib/feed';
import { getIdentity, type IdentityInfo } from '@/lib/api';
import { safeBack } from '@/lib/utils';

const PAGE = 30;

function shortAddr(a: string, n = 6): string {
  if (!a) return '—';
  return a.length <= n * 2 + 1 ? a : `${a.slice(0, n)}…${a.slice(-n)}`;
}

export default function AuthorWallScreen() {
  const insets = useSafeAreaInsets();
  const { pub } = useLocalSearchParams<{ pub: string }>();
  const keyFile  = useStore(s => s.keyFile);
  const contacts = useStore(s => s.contacts);

  const contact  = contacts.find(c => c.address === pub);
  const isMe     = !!keyFile && keyFile.pub_key === pub;

  const [posts, setPosts]             = useState<FeedPostItem[]>([]);
  const [likedSet, setLikedSet]       = useState<Set<string>>(new Set());
  const [loading, setLoading]         = useState(true);
  const [refreshing, setRefreshing]   = useState(false);
  const [loadingMore, setLoadingMore] = useState(false);
  const [exhausted, setExhausted]     = useState(false);
  const [identity, setIdentity]       = useState<IdentityInfo | null>(null);

  const seq = useRef(0);

  // Identity — for the header's username / avatar seed. Best-effort; the
  // screen still works without it.
  useEffect(() => {
    if (!pub) return;
    let cancelled = false;
    getIdentity(pub).then(id => { if (!cancelled) setIdentity(id); }).catch(() => {});
    return () => { cancelled = true; };
  }, [pub]);

  const loadLikedFor = useCallback(async (items: FeedPostItem[]) => {
    if (!keyFile) return new Set<string>();
    const liked = new Set<string>();
    for (const p of items) {
      const s = await fetchStats(p.post_id, keyFile.pub_key);
      if (s?.liked_by_me) liked.add(p.post_id);
    }
    return liked;
  }, [keyFile]);

  const load = useCallback(async (isRefresh = false) => {
    if (!pub) return;
    if (isRefresh) setRefreshing(true);
    else setLoading(true);

    const id = ++seq.current;
    try {
      const items = await fetchAuthorPosts(pub, { limit: PAGE });
      if (id !== seq.current) return;
      setPosts(items);
      setExhausted(items.length < PAGE);
      const liked = await loadLikedFor(items);
      if (id !== seq.current) return;
      setLikedSet(liked);
    } catch {
      if (id !== seq.current) return;
      setPosts([]);
      setExhausted(true);
    } finally {
      if (id !== seq.current) return;
      setLoading(false);
      setRefreshing(false);
    }
  }, [pub, loadLikedFor]);

  useEffect(() => { load(false); }, [load]);

  const loadMore = useCallback(async () => {
    if (!pub || loadingMore || exhausted || loading) return;
    const oldest = posts[posts.length - 1];
    if (!oldest) return;
    setLoadingMore(true);
    try {
      const more = await fetchAuthorPosts(pub, { limit: PAGE, before: oldest.created_at });
      // De-dup by post_id — defensive against boundary overlap.
      const known = new Set(posts.map(p => p.post_id));
      const fresh = more.filter(p => !known.has(p.post_id));
      if (fresh.length === 0) { setExhausted(true); return; }
      setPosts(prev => [...prev, ...fresh]);
      if (more.length < PAGE) setExhausted(true);
      const liked = await loadLikedFor(fresh);
      setLikedSet(set => {
        const next = new Set(set);
        liked.forEach(v => next.add(v));
        return next;
      });
    } catch {
      // Swallow — user can pull-to-refresh to recover.
    } finally {
      setLoadingMore(false);
    }
  }, [pub, posts, loadingMore, exhausted, loading, loadLikedFor]);

  const onStatsChanged = useCallback(async (postID: string) => {
    if (!keyFile) return;
    const s = await fetchStats(postID, keyFile.pub_key);
    if (!s) return;
    setPosts(ps => ps.map(p => p.post_id === postID
      ? { ...p, likes: s.likes, views: s.views } : p));
    setLikedSet(set => {
      const next = new Set(set);
      if (s.liked_by_me) next.add(postID); else next.delete(postID);
      return next;
    });
  }, [keyFile]);

  // "Saved Messages" is a messaging-app label and has no place on a public
  // wall — for self we fall back to the real handle (@username if claimed,
  // else short-addr), same as any other author.
  const displayName = isMe
    ? (identity?.nickname ? `@${identity.nickname}` : 'You')
    : contact?.username
      ? `@${contact.username}`
      : (contact?.alias && contact.alias !== 'Saved Messages')
        ? contact.alias
        : (identity?.nickname ? `@${identity.nickname}` : shortAddr(pub ?? '', 6));

  const handle = identity?.nickname ? `@${identity.nickname}` : shortAddr(pub ?? '', 6);

  return (
    <View style={{ flex: 1, backgroundColor: '#000000', paddingTop: insets.top }}>
      <Header
        divider
        left={<IconButton icon="chevron-back" size={36} onPress={() => safeBack()} />}
        title={
          <Pressable
            onPress={() => pub && router.push(`/(app)/profile/${pub}` as never)}
            hitSlop={4}
            style={{ flexDirection: 'row', alignItems: 'center', gap: 8, maxWidth: '100%' }}
          >
            <Avatar name={displayName} address={pub} size={28} />
            <View style={{ minWidth: 0, flexShrink: 1 }}>
              <Text
                numberOfLines={1}
                style={{
                  color: '#ffffff', fontSize: 15, fontWeight: '700', letterSpacing: -0.2,
                }}
              >
                {displayName}
              </Text>
              <Text style={{ color: '#8b8b8b', fontSize: 11 }} numberOfLines={1}>
                {handle !== displayName ? handle : 'Wall'}
              </Text>
            </View>
          </Pressable>
        }
      />

      <FlatList
        data={posts}
        keyExtractor={p => p.post_id}
        renderItem={({ item }) => (
          <PostCard
            post={item}
            likedByMe={likedSet.has(item.post_id)}
            onStatsChanged={onStatsChanged}
          />
        )}
        ItemSeparatorComponent={PostSeparator}
        initialNumToRender={10}
        maxToRenderPerBatch={8}
        windowSize={7}
        removeClippedSubviews
        onEndReachedThreshold={0.6}
        onEndReached={loadMore}
        refreshControl={
          <RefreshControl
            refreshing={refreshing}
            onRefresh={() => load(true)}
            tintColor="#1d9bf0"
          />
        }
        ListFooterComponent={
          loadingMore ? (
            <View style={{ paddingVertical: 18 }}>
              <ActivityIndicator color="#1d9bf0" />
            </View>
          ) : null
        }
        ListEmptyComponent={
          loading ? (
            <View style={{ paddingTop: 80, alignItems: 'center' }}>
              <ActivityIndicator color="#1d9bf0" />
            </View>
          ) : (
            <View style={{
              flex: 1,
              alignItems: 'center', justifyContent: 'center',
              paddingHorizontal: 32, paddingVertical: 80,
            }}>
              <Ionicons name="document-text-outline" size={32} color="#6a6a6a" />
              <Text style={{ color: '#ffffff', fontWeight: '700', marginTop: 10 }}>
                {isMe ? "You haven't posted yet" : 'No posts yet'}
              </Text>
              <Text style={{ color: '#8b8b8b', textAlign: 'center', fontSize: 13, marginTop: 6 }}>
                {isMe
                  ? 'Tap the compose button on the feed tab to publish your first post.'
                  : 'This user hasn\'t published any posts on this chain.'}
              </Text>
            </View>
          )
        }
        contentContainerStyle={
          posts.length === 0
            ? { flexGrow: 1 }
            : { paddingTop: 8, paddingBottom: 24 }
        }
      />
    </View>
  );
}
