import { useCallback, useEffect, useRef, useState } from 'react'
import Taro from '@tarojs/taro'
import { ScrollView, Text, View } from '@tarojs/components'
import CustomNavBar from '@/components/layout/CustomNavBar'
import PageShell from '@/components/layout/PageShell'
import SearchBar from '@/components/ui/SearchBar'
import SegmentedTabs from '@/components/ui/SegmentedTabs'
import Chip from '@/components/ui/Chip'
import ToastOverlay from '@/components/feedback/ToastOverlay'
import FeedAdCard from '@/features/feed/components/FeedAdCard'
import PostCard from '@/features/feed/components/PostCard'
import { getFeedList, setPostLike } from '@/services/feed.service'
import { useToast } from '@/hooks/useToast'
import { useTabRefresh } from '@/hooks/useTabRefresh'
import { cachePost, markFresh, onPostLike } from '@/store/dataBus'
import { ensureProfileReady } from '@/store/session.store'
import type { TabViewProps } from '@/components/navigation/BottomTabBar/tabConfig'
import type { FeedChannel, Post } from '@/types/domain'
import './index.scss'

const tabs = [
  { key: 'feed', label: '推荐' },
  { key: 'nearby', label: '附近' },
  { key: 'follow', label: '关注' }
] as const

const ALL_TOPIC = '全部'
const PAGE_SIZE = 20
const AD_INTERVAL = 6
const INITIAL_TOPICS = [ALL_TOPIC]

interface LoadFeedOptions {
  append?: boolean
  cursor?: string
  // Silent refresh keeps the current list visible (no blank/loading flash) while
  // fetching the latest first page in the background.
  silent?: boolean
}

interface LikeOverride {
  likedByMe: boolean
  likes: number
}

function createAdStartIndex(): number {
  return 1 + Math.floor(Math.random() * 3)
}

function mergePosts(current: Post[], incoming: Post[]): Post[] {
  const seen = new Set(current.map(post => post._id))
  return [...current, ...incoming.filter(post => !seen.has(post._id))]
}

function normalizeTopicOptions(topics: string[] = [], selectedTopic = ALL_TOPIC): string[] {
  const next = [...INITIAL_TOPICS]
  const seen = new Set(next)

  if (selectedTopic !== ALL_TOPIC) {
    next.push(selectedTopic)
    seen.add(selectedTopic)
  }

  topics.forEach(item => {
    if (!item || seen.has(item)) return
    next.push(item)
    seen.add(item)
  })

  return next
}

function applyPendingPostState(
  list: Post[],
  likeOverrides: Map<string, LikeOverride>
): Post[] {
  return list.map(post => {
    const like = likeOverrides.get(post._id)
    if (!like) return post

    return {
      ...post,
      likedByMe: like.likedByMe,
      counts: {
        ...post.counts,
        likes: like.likes
      }
    }
  })
}

export default function PlazaPage({ active = false, showTick = 0 }: TabViewProps) {
  const [channel, setChannel] = useState<FeedChannel>('feed')
  const [topic, setTopic] = useState(ALL_TOPIC)
  const [topicOptions, setTopicOptions] = useState(INITIAL_TOPICS)
  const [keyword, setKeyword] = useState('')
  const [debouncedKeyword, setDebouncedKeyword] = useState('')
  const [posts, setPosts] = useState<Post[]>([])
  const [nextCursor, setNextCursor] = useState('')
  const [loading, setLoading] = useState(true)
  const [loadingMore, setLoadingMore] = useState(false)
  const [adStartIndex, setAdStartIndex] = useState(createAdStartIndex)
  const toast = useToast(480)
  const postsRef = useRef<Post[]>([])
  const feedRequestSeq = useRef(0)
  const pendingLikeIds = useRef(new Set<string>())
  const pendingLikeOverrides = useRef(new Map<string, LikeOverride>())

  const invalidateFeedRequests = () => {
    feedRequestSeq.current += 1
  }

  const loadFeed = useCallback(async ({ append = false, cursor, silent = false }: LoadFeedOptions = {}) => {
    const requestId = feedRequestSeq.current + 1
    feedRequestSeq.current = requestId
    if (append) {
      setLoadingMore(true)
    } else if (!silent) {
      // Keep the existing content visible until fresh data arrives so search
      // and filter changes do not flash a blank list.
      setLoading(true)
      setNextCursor('')
    }

    try {
      const result = await getFeedList({
        channel,
        topic: topic === ALL_TOPIC ? undefined : topic,
        cursor,
        pageSize: PAGE_SIZE,
        keyword: debouncedKeyword || undefined
      })

      if (requestId !== feedRequestSeq.current) return

      const hydratedPosts = applyPendingPostState(
        result.list,
        pendingLikeOverrides.current
      )
      setPosts(current => (append ? mergePosts(current, hydratedPosts) : hydratedPosts))
      setNextCursor(result.nextCursor || '')
      if (!append) {
        setTopicOptions(normalizeTopicOptions(result.topics, topic))
        setAdStartIndex(createAdStartIndex())
        markFresh('feed')
      }
    } catch {
      if (requestId === feedRequestSeq.current) {
        Taro.showToast({ title: '动态加载失败，请重试', icon: 'none' })
      }
    } finally {
      if (append) setLoadingMore(false)
      else setLoading(false)
    }
  }, [channel, debouncedKeyword, topic])

  useEffect(() => {
    loadFeed()
  }, [loadFeed])

  useEffect(() => {
    postsRef.current = posts
  }, [posts])

  useEffect(() => {
    const timer = setTimeout(() => setDebouncedKeyword(keyword.trim()), 300)
    return () => clearTimeout(timer)
  }, [keyword])

  const commitSearch = () => {
    setDebouncedKeyword(keyword.trim())
  }

  const clearSearch = () => {
    setKeyword('')
    setDebouncedKeyword('')
  }

  // Refresh on return only when the feed is stale (e.g. after publishing) or the
  // TTL elapsed, and do it silently so the list never flashes blank.
  useTabRefresh('feed', active, showTick, () => loadFeed({ silent: true }))

  // Keep posts in sync when liked from another page (e.g. the detail page).
  useEffect(() => onPostLike(({ postId, liked, likes }) => {
    setPosts(current => current.map(post => (
      post._id === postId
        ? post.likedByMe === liked && post.counts.likes === likes
          ? post
          : { ...post, likedByMe: liked, counts: { ...post.counts, likes } }
        : post
    )))
  }), [])

  const loadNextPage = () => {
    if (loading || loadingMore || !nextCursor) return
    loadFeed({ append: true, cursor: nextCursor })
  }

  const likePost = async (postId: string) => {
    if (!(await ensureProfileReady())) return
    if (pendingLikeIds.current.has(postId)) return

    const previousPost = postsRef.current.find(post => post._id === postId)
    if (!previousPost) return

    const likedByMe = !previousPost.likedByMe
    const likes = Math.max(0, previousPost.counts.likes + (likedByMe ? 1 : -1))
    pendingLikeIds.current.add(postId)
    pendingLikeOverrides.current.set(postId, { likedByMe, likes })
    invalidateFeedRequests()
    if (likedByMe) toast.show()

    setPosts(current => current.map(post => {
      if (post._id !== postId) return post
      return { ...post, likedByMe, counts: { ...post.counts, likes } }
    }))

    try {
      const result = await setPostLike(postId, likedByMe)
      pendingLikeOverrides.current.delete(postId)
      invalidateFeedRequests()
      setPosts(current => current.map(post => (
        post._id === postId
          ? { ...post, likedByMe: result.liked, counts: { ...post.counts, likes: result.likes } }
          : post
      )))
    } catch {
      pendingLikeOverrides.current.delete(postId)
      invalidateFeedRequests()
      setPosts(current => current.map(post => (
        post._id === postId
          ? {
            ...post,
            likedByMe: previousPost.likedByMe,
            counts: { ...post.counts, likes: previousPost.counts.likes }
          }
          : post
      )))
      Taro.showToast({ title: '点赞失败，请重试', icon: 'none' })
    } finally {
      pendingLikeIds.current.delete(postId)
    }
  }

  const openPost = (postId: string) => {
    // Hand the already-loaded post (with resolved image URLs) to the detail page
    // so it paints instantly instead of waiting on its own fetch.
    const post = postsRef.current.find(item => item._id === postId)
    if (post) cachePost(post)
    Taro.navigateTo({ url: `/pages/post-detail/index?postId=${postId}` })
  }

  const shouldShowFeedAd = (index: number) => (
    index >= adStartIndex && (index - adStartIndex) % AD_INTERVAL === 0
  )
  const resultCountText = nextCursor ? `${posts.length}+` : String(posts.length)
  const emptyText = debouncedKeyword
    ? '没有找到相关动态，换个关键词试试吧'
    : channel === 'follow'
      ? '关注的人还没有发布动态，去发现更多汪友吧'
      : '还没有动态，点击 + 发布第一条吧'

  return (
    <PageShell className='plaza-page' lowerThreshold={160} onScrollToLower={loadNextPage}>
      <CustomNavBar title='广场' />
      <SearchBar
        placeholder='搜索话题、宠物、附近活动'
        value={keyword}
        onInput={setKeyword}
        onConfirm={commitSearch}
      />
      <SegmentedTabs items={tabs as any} value={channel} onChange={setChannel} />
      <ScrollView scrollX className='plaza-page__chips' showScrollbar={false}>
        <View className='plaza-page__chips-inner'>
          {topicOptions.map(item => (
            <Chip key={item} active={topic === item} onClick={() => setTopic(item)}>
              {item}
            </Chip>
          ))}
        </View>
      </ScrollView>
      {debouncedKeyword ? (
        <View className='plaza-page__search-result'>
          <View className='plaza-page__search-copy'>
            <Text className='plaza-page__search-title'>
              {topic === ALL_TOPIC ? `搜索“${debouncedKeyword}”` : `在 #${topic} 中搜索“${debouncedKeyword}”`}
            </Text>
            <Text className='plaza-page__search-count'>
              {loading ? '正在搜索…' : `已展示 ${resultCountText} 条结果`}
            </Text>
          </View>
          <Text className='plaza-page__search-clear' onClick={clearSearch}>清除</Text>
        </View>
      ) : null}
      <View className='plaza-page__feed'>
        {posts.map((post, index) => (
          <View key={post._id}>
            <PostCard post={post} onLike={likePost} onOpen={openPost} />
            {shouldShowFeedAd(index) ? <FeedAdCard /> : null}
          </View>
        ))}
        {loading && posts.length === 0 ? (
          <Text className='plaza-page__empty'>加载中…</Text>
        ) : !loading && posts.length === 0 ? (
          <Text className='plaza-page__empty'>{emptyText}</Text>
        ) : loadingMore ? (
          <Text className='plaza-page__empty'>加载更多中…</Text>
        ) : !nextCursor ? (
          <Text className='plaza-page__empty'>暂时没有更多了，稍后再来看看吧</Text>
        ) : (
          <Text className='plaza-page__empty'>上滑加载更多</Text>
        )}
      </View>
      <ToastOverlay visible={toast.visible} />
    </PageShell>
  )
}
