import { DEFAULT_FAVORITE_RELAYS } from '@/constants'
import { getFavoritesFeedRelayUrls } from '@/lib/favorites-feed-relays'
import { getRelaySetFromEvent } from '@/lib/event-metadata'
import logger from '@/lib/logger'
import { isHttpRelayUrl, isWebsocketUrl, normalizeAnyRelayUrl } from '@/lib/url'
import indexedDb from '@/services/indexed-db.service'
import storage from '@/services/local-storage.service'
import { TFeedInfo, TFeedType } from '@/types'
import { kinds } from 'nostr-tools'
import { useEffect, useRef, useState, useCallback } from 'react'
import { FeedContext } from './feed-context'
import { useFavoriteRelays } from './FavoriteRelaysProvider'
import { useNostr } from './NostrProvider'

export { useFeed } from './feed-context'
export type { TFeedContext } from './feed-context'

export function FeedProvider({ children }: { children: React.ReactNode }) {
  const { pubkey, isInitialized } = useNostr()
  const { relaySets, favoriteRelays, blockedRelays } = useFavoriteRelays()
  const [relayUrls, setRelayUrls] = useState<string[]>([])
  const [isReady, setIsReady] = useState(false)
  const [feedInfo, setFeedInfo] = useState<TFeedInfo>({
    feedType: 'relay',
    id: DEFAULT_FAVORITE_RELAYS[0]
  })
  const feedInfoRef = useRef<TFeedInfo>(feedInfo)
  const loggedWaitingForNostrInitRef = useRef(false)

  const switchFeed = useCallback(async (
    feedType: TFeedType,
    options: {
      activeRelaySetId?: string | null
      pubkey?: string | null
      relay?: string | null
    } = {}
  ) => {
    logger.debug('switchFeed called:', { feedType, options })
    setIsReady(false)
    if (feedType === 'relay') {
      const normalizedUrl = normalizeAnyRelayUrl(options.relay ?? '')
      const isRelayFeedUrl =
        !!normalizedUrl && (isHttpRelayUrl(normalizedUrl) || isWebsocketUrl(normalizedUrl))
      logger.debug('Relay switchFeed:', { normalizedUrl, isRelayFeedUrl, blockedRelays })

      if (!isRelayFeedUrl) {
        logger.debug('Invalid relay URL, setting isReady to true')
        setIsReady(true)
        return
      }
      
      // Don't allow selecting a blocked relay as feed
      if (blockedRelays.includes(normalizedUrl)) {
        logger.warn('Cannot select blocked relay as feed:', normalizedUrl)
        setIsReady(true)
        return
      }

      const newFeedInfo = { feedType, id: normalizedUrl }
      logger.component('FeedProvider', 'Setting relay feed info', newFeedInfo)
      setFeedInfo(newFeedInfo)
      feedInfoRef.current = newFeedInfo
      setRelayUrls([normalizedUrl])
      logger.component('FeedProvider', 'Set relayUrls', { relayUrls: [normalizedUrl] })
      storage.setFeedInfo(newFeedInfo, pubkey)
      // Reset note list mode to 'posts' when switching to relay feed to ensure main content is shown
      storage.setNoteListMode('posts')
      setIsReady(true)
      logger.component('FeedProvider', 'Relay feed setup complete, isReady set to true')
      return
    }
    if (feedType === 'relays') {
      const relaySetId = options.activeRelaySetId ?? (relaySets.length > 0 ? relaySets[0].id : null)
      if (!relaySetId || !pubkey) {
        setIsReady(true)
        return
      }

      let relaySet =
        relaySets.find((set) => set.id === relaySetId) ??
        (relaySets.length > 0 ? relaySets[0] : null)
      if (!relaySet) {
        const storedRelaySetEvent = await indexedDb.getReplaceableEvent(
          pubkey,
          kinds.Relaysets,
          relaySetId
        )
        if (storedRelaySetEvent) {
          relaySet = getRelaySetFromEvent(storedRelaySetEvent, blockedRelays)
        }
      }
      if (relaySet) {
        const newFeedInfo = { feedType, id: relaySet.id }
        setFeedInfo(newFeedInfo)
        feedInfoRef.current = newFeedInfo
        setRelayUrls(relaySet.relayUrls)
        storage.setFeedInfo(newFeedInfo, pubkey)
        // Reset note list mode to 'posts' when switching to relay set to ensure main content is shown
        storage.setNoteListMode('posts')
        setIsReady(true)
      }
      setIsReady(true)
      return
    }
    if (feedType === 'all-favorites') {
      const finalRelays = getFavoritesFeedRelayUrls(favoriteRelays, blockedRelays)
      logger.debug('Switching to all-favorites, finalRelays:', finalRelays)
      const newFeedInfo = { feedType }
      setFeedInfo(newFeedInfo)
      feedInfoRef.current = newFeedInfo
      setRelayUrls(finalRelays)
      storage.setFeedInfo(newFeedInfo, pubkey)
      // Reset note list mode to 'posts' when switching to all-favorites to ensure main content is shown
      storage.setNoteListMode('posts')
      setIsReady(true)
      return
    }
    setIsReady(true)
  }, [pubkey, favoriteRelays, blockedRelays, relaySets])

  useEffect(() => {
    const init = async () => {
      logger.debug('FeedProvider init:', { isInitialized, pubkey, favoriteRelays: favoriteRelays.length, blockedRelays: blockedRelays.length })
      if (!isInitialized) {
        if (!loggedWaitingForNostrInitRef.current) {
          loggedWaitingForNostrInitRef.current = true
          logger.info(
            '[FeedProvider] Waiting for Nostr session restore before attaching feeds (home may show a loading state)'
          )
        }
        return
      }
      loggedWaitingForNostrInitRef.current = false

      // Wait for favoriteRelays to be initialized (should have at least default relays)
      // If favoriteRelays is empty, it might not be initialized yet, so wait
      if (favoriteRelays.length === 0 && !pubkey) {
        // For anonymous users, favoriteRelays should be initialized from FAST_READ_RELAY_URLS
        // If it's still empty, something is wrong, but we'll use defaults
        logger.debug('FeedProvider: favoriteRelays is empty, using defaults')
      }

      const favoritesFeedRelays = getFavoritesFeedRelayUrls(favoriteRelays, blockedRelays)
      let feedInfo: TFeedInfo = {
        feedType: 'relay',
        id: favoritesFeedRelays[0] ?? DEFAULT_FAVORITE_RELAYS[0]
      }

      // Ensure we always have a valid relay ID
      if (!feedInfo.id) {
        feedInfo.id = DEFAULT_FAVORITE_RELAYS[0]
      }
      logger.debug('Initial feedInfo setup:', { favoritesFeedRelays, favoriteRelays, blockedRelays, feedInfo })
      
      if (pubkey) {
        const storedFeedInfo = storage.getFeedInfo(pubkey)
        logger.debug('Stored feed info:', storedFeedInfo)
        if (storedFeedInfo) {
          feedInfo = storedFeedInfo
        }
      }

      // Pre-rewrite main feeds (`following`, `bookmarks`) are no longer supported; migrate persisted state.
      const storedFeedType = (feedInfo as { feedType?: string }).feedType
      const deprecatedMainFeed = storedFeedType === 'following' || storedFeedType === 'bookmarks'
      if (deprecatedMainFeed) {
        const previousMainFeed = storedFeedType
        const migrated: TFeedInfo = { feedType: 'all-favorites' }
        feedInfo = migrated
        if (pubkey) {
          storage.setFeedInfo(migrated, pubkey)
        }
        logger.info('[FeedProvider] Migrated deprecated feed type to all-favorites', {
          previous: previousMainFeed
        })
        return await switchFeed('all-favorites')
      }

      if (feedInfo.feedType === 'relays') {
        return await switchFeed('relays', { activeRelaySetId: feedInfo.id })
      }

      if (feedInfo.feedType === 'relay') {
        // Check if the stored relay is blocked, if so use first visible relay instead
        if (feedInfo.id && blockedRelays.includes(feedInfo.id)) {
          logger.component('FeedProvider', 'Stored relay is blocked, using first visible relay instead')
          feedInfo.id = favoritesFeedRelays[0] ?? DEFAULT_FAVORITE_RELAYS[0]
        }
        logger.component('FeedProvider', 'Initial relay setup, calling switchFeed', { relayId: feedInfo.id })
        return await switchFeed('relay', { relay: feedInfo.id })
      }

      if (feedInfo.feedType === 'all-favorites') {
        logger.debug('Initializing all-favorites feed')
        return await switchFeed('all-favorites')
      }
    }

    init()
  }, [pubkey, isInitialized, favoriteRelays, blockedRelays, switchFeed])

  // Update relay URLs when favoriteRelays change and we're in all-favorites mode
  useEffect(() => {
    if (feedInfo.feedType !== 'all-favorites') return
    const finalRelays = getFavoritesFeedRelayUrls(favoriteRelays, blockedRelays)
    logger.debug('Updating relay URLs for all-favorites:', finalRelays)
    setRelayUrls(finalRelays)
  }, [feedInfo.feedType, favoriteRelays, blockedRelays])

  return (
    <FeedContext.Provider
      value={{
        feedInfo,
        relayUrls,
        isReady,
        switchFeed
      }}
    >
      {children}
    </FeedContext.Provider>
  )
}
