import NormalFeed from '@/components/NormalFeed'
import type { TNoteListRef } from '@/components/NoteList'
import { SINGLE_RELAY_KINDLESS_REQ_LIMIT } from '@/constants'
import { checkAlgoRelay } from '@/lib/relay'
import {
  isWispTrendingNotesRelayUrl,
  WISP_TRENDING_FEED_KINDS
} from '@/lib/wisp-trending-relay'
import { normalizeUrl } from '@/lib/url'
import { useFeed } from '@/providers/FeedProvider'
import { useKindFilterOrDefaults } from '@/providers/KindFilterProvider'
import relayInfoService from '@/services/relay-info.service'
import { kinds } from 'nostr-tools'
import React, { forwardRef, useCallback, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'

const RelaysFeed = forwardRef<
  TNoteListRef,
  {
    setSubHeader?: (node: React.ReactNode) => void
    onSubHeaderRefresh?: () => void
    /** When set, subscription kinds (fixed list); otherwise uses KindFilterProvider. */
    kindsOverride?: number[]
  }
>(function RelaysFeed({ setSubHeader, onSubHeaderRefresh, kindsOverride }, ref) {
  const { t } = useTranslation()
  const { feedInfo, relayUrls } = useFeed()
  const { showKinds } = useKindFilterOrDefaults()
  const [areAlgoRelays, setAreAlgoRelays] = useState(false)
  /** After kindless single-relay REQ EOSEs with no events, re-subscribe with the normal kind list. */
  const [singleRelayKindFallback, setSingleRelayKindFallback] = useState(false)

  const relayUrlsKey = useMemo(
    () =>
      [...relayUrls]
        .map((u) => normalizeUrl(u) || u)
        .filter(Boolean)
        .sort()
        .join('|'),
    [relayUrls]
  )

  useEffect(() => {
    if (relayUrls.length === 0) {
      setAreAlgoRelays(false)
      return
    }
    let cancelled = false

    const init = async () => {
      const timeoutPromise = new Promise<never>((_, reject) => {
        setTimeout(() => {
          reject(new Error('getRelayInfos timeout after 8 seconds'))
        }, 8000)
      })

      try {
        const relayInfos = await Promise.race([
          relayInfoService.getRelayInfos(relayUrls),
          timeoutPromise
        ])
        if (cancelled) return
        const areAlgo = relayInfos.every((relayInfo) => checkAlgoRelay(relayInfo))
        setAreAlgoRelays(areAlgo)
      } catch (_error) {
        if (!cancelled) setAreAlgoRelays(false)
      }
    }

    void init()
    return () => {
      cancelled = true
    }
  }, [relayUrlsKey, relayUrls.length])

  /** Stable identity when kind filter is empty so `subRequests` does not invalidate every render. */
  const fallbackNoteKinds = useMemo(() => [kinds.ShortTextNote], [])
  const defaultKinds = useMemo(() => {
    if (kindsOverride && kindsOverride.length > 0) return kindsOverride
    if (showKinds.length > 0) return showKinds
    return fallbackNoteKinds
  }, [kindsOverride, showKinds, fallbackNoteKinds])

  const canRenderFeed =
    (feedInfo.feedType === 'relay' ||
      feedInfo.feedType === 'relays' ||
      feedInfo.feedType === 'all-favorites') &&
    relayUrls.length > 0

  /** Distinguishes home relay chips so we do not keep the previous timeline on single→all-favorites (strict superset). */
  const feedTimelineScopeKey = useMemo(() => {
    if (feedInfo.feedType === 'all-favorites') return 'all-favorites'
    if (feedInfo.feedType === 'relays') return `relays:${feedInfo.id ?? ''}`
    if (feedInfo.feedType === 'relay') {
      const id = feedInfo.id ? normalizeUrl(feedInfo.id) || feedInfo.id : ''
      return `relay:${id}`
    }
    return undefined
  }, [feedInfo.feedType, feedInfo.id])

  const wispTrendingSingleRelay =
    feedInfo.feedType === 'relay' &&
    relayUrls.length === 1 &&
    !!relayUrls[0] &&
    isWispTrendingNotesRelayUrl(relayUrls[0])

  /** New relay chip / set: try kindless first again. */
  useEffect(() => {
    setSingleRelayKindFallback(false)
  }, [feedTimelineScopeKey])

  const onSingleRelayKindlessEmpty = useCallback(() => {
    setSingleRelayKindFallback(true)
  }, [])

  /**
   * One relay + user kind filter: kindless `{ limit }` REQ first (many relays error on huge `kinds` arrays).
   * If that EOSEs with no events, `onSingleRelayKindlessEmpty` switches to explicit `kinds`.
   */
  const singleRelayKindlessExplore =
    feedInfo.feedType === 'relay' &&
    relayUrls.length === 1 &&
    !kindsOverride?.length &&
    !singleRelayKindFallback &&
    !wispTrendingSingleRelay

  const feedTopNotice = singleRelayKindFallback ? (
    <p className="leading-snug">{t('singleRelayKindFallbackNotice')}</p>
  ) : null

  // Hooks must run every render — never place useMemo after conditional returns.
  const subRequests = useMemo(() => {
    if (!canRenderFeed) return []
    if (wispTrendingSingleRelay) {
      return [
        {
          urls: relayUrls,
          filter: { kinds: [...WISP_TRENDING_FEED_KINDS], limit: 100 }
        }
      ]
    }
    if (singleRelayKindlessExplore) {
      return [{ urls: relayUrls, filter: { limit: SINGLE_RELAY_KINDLESS_REQ_LIMIT } }]
    }
    return [
      {
        urls: relayUrls,
        filter: {
          kinds: defaultKinds
        }
      }
    ]
  }, [
    canRenderFeed,
    relayUrls,
    defaultKinds,
    kindsOverride,
    singleRelayKindlessExplore,
    wispTrendingSingleRelay
  ])

  if (!canRenderFeed) {
    return null
  }

  // preserveTimeline: merge when relay list grows (e.g. all-favorites list fills in). Do not use
  // mergeTimelineWhenSubRequestFiltersMatch here — same kinds + different URLs would keep the old
  // timeline when switching home feed chips (all-favorites ↔ set ↔ single relay).
  return (
    <NormalFeed
      ref={ref}
      subRequests={subRequests}
      areAlgoRelays={wispTrendingSingleRelay || areAlgoRelays}
      isMainFeed
      setSubHeader={setSubHeader}
      onSubHeaderRefresh={onSubHeaderRefresh}
      preserveTimelineOnSubRequestsChange
      feedTimelineScopeKey={feedTimelineScopeKey}
      useFilterAsIs={singleRelayKindlessExplore}
      allowKindlessRelayExplore={singleRelayKindlessExplore}
      clientSideKindFilter={singleRelayKindlessExplore}
      showFeedClientFilter
      hostPrimaryPageName="feed"
      onSingleRelayKindlessEmpty={
        feedInfo.feedType === 'relay' && relayUrls.length === 1 && !kindsOverride?.length
          ? onSingleRelayKindlessEmpty
          : undefined
      }
      feedTopNotice={feedTopNotice}
    />
  )
})

RelaysFeed.displayName = 'RelaysFeed'
export default RelaysFeed
