import { useEffect, useState, useMemo, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { useNostr } from '@/providers/NostrProvider'
import rssFeedService, { RssFeedItem as TRssFeedItem } from '@/services/rss-feed.service'
import { DEFAULT_RSS_FEEDS } from '@/constants'
import RssFeedItem from '../RssFeedItem'
import { Loader, AlertCircle, Search, Plus } from 'lucide-react'
import logger from '@/lib/logger'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import { Input } from '@/components/ui/input'
import { Switch } from '@/components/ui/switch'
import { Label } from '@/components/ui/label'
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
import { Button } from '@/components/ui/button'
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle
} from '@/components/ui/dialog'
import { useScreenSize } from '@/providers/ScreenSizeProvider'
import { Check, ChevronDown } from 'lucide-react'
import { useSmartRssArticleNavigation } from '@/PageManager'
import { normalizeHttpArticleUrl } from '@/lib/rss-article'

function ManualRssUrlAddRow({ className }: { className?: string }) {
  const { t } = useTranslation()
  const { navigateToRssArticle } = useSmartRssArticleNavigation()
  const [open, setOpen] = useState(false)
  const [value, setValue] = useState('')
  const [error, setError] = useState('')

  const submit = () => {
    setError('')
    const url = normalizeHttpArticleUrl(value)
    if (!url) {
      setError(t('Enter a valid http(s) URL'))
      return
    }
    setOpen(false)
    setValue('')
    navigateToRssArticle(url)
  }

  return (
    <>
      <Button
        type="button"
        variant="outline"
        className={className ?? 'w-full justify-start gap-2 text-muted-foreground border-dashed'}
        onClick={() => setOpen(true)}
      >
        <Plus className="h-4 w-4 shrink-0" />
        {t('+ Add a URL to this list')}
      </Button>
      <Dialog open={open} onOpenChange={setOpen}>
        <DialogContent className="sm:max-w-md">
          <DialogHeader>
            <DialogTitle>{t('Add a web URL')}</DialogTitle>
            <DialogDescription>
              {t('Open any https page in the side panel to reply, react, and discuss on Nostr.')}
            </DialogDescription>
          </DialogHeader>
          <Input
            placeholder="https://example.com/article"
            value={value}
            onChange={(e) => {
              setValue(e.target.value)
              setError('')
            }}
            onKeyDown={(e) => {
              if (e.key === 'Enter') {
                e.preventDefault()
                submit()
              }
            }}
            autoFocus
          />
          {error ? <p className="text-sm text-destructive">{error}</p> : null}
          <DialogFooter className="gap-2 sm:gap-0">
            <Button type="button" variant="secondary" onClick={() => setOpen(false)}>
              {t('Cancel')}
            </Button>
            <Button type="button" onClick={submit}>
              {t('Open')}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </>
  )
}

export default function RssFeedList() {
  const { t } = useTranslation()
  const { pubkey, rssFeedListEvent } = useNostr()
  const { isSmallScreen } = useScreenSize()
  const [items, setItems] = useState<TRssFeedItem[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [refreshing, setRefreshing] = useState(false)
  
  // Filter states
  const [selectedFeeds, setSelectedFeeds] = useState<string[]>(['all'])
  const [timeFilter, setTimeFilter] = useState<string>('all')
  const [searchQuery, setSearchQuery] = useState<string>('')
  const [showFilters, setShowFilters] = useState<boolean>(false)
  const [isCompactView, setIsCompactView] = useState<boolean>(true)
  const [feedPopoverOpen, setFeedPopoverOpen] = useState<boolean>(false)
  
  // Pagination state
  const [showCount, setShowCount] = useState<number>(25)
  const bottomRef = useRef<HTMLDivElement>(null)

  // Listen for filter toggle events
  useEffect(() => {
    const handleToggleFilters = () => {
      setShowFilters(prev => !prev)
    }

    window.addEventListener('toggleRssFilters', handleToggleFilters)
    return () => {
      window.removeEventListener('toggleRssFilters', handleToggleFilters)
    }
  }, [])

  useEffect(() => {
    // Create AbortController for this effect
    let abortController = new AbortController()
    let isMounted = true
    let isLoading = false
    let timeoutId: NodeJS.Timeout | null = null

    const loadRssFeeds = async (forceNewController = false) => {
      // If forced, create a new controller (for manual refreshes)
      if (forceNewController) {
        abortController.abort() // Abort old one
        abortController = new AbortController()
      }

      // Check if already aborted or if a load is already in progress
      if (abortController.signal.aborted || isLoading) {
        logger.debug('[RssFeedList] Skipping load - already aborted or loading', { 
          aborted: abortController.signal.aborted, 
          isLoading 
        })
        return
      }

      // Clear any existing timeout
      if (timeoutId) {
        clearTimeout(timeoutId)
        timeoutId = null
      }

      isLoading = true
      setLoading(true)
      setError(null)
      
      // Set a timeout to prevent infinite loading (30 seconds)
      timeoutId = setTimeout(() => {
        if (isMounted && isLoading) {
          logger.warn('[RssFeedList] Feed loading timeout - aborting and showing partial results')
          abortController.abort()
          isLoading = false
          if (isMounted) {
            setLoading(false)
          }
        }
      }, 30000)

      try {
        // Get feed URLs from event or use default
        let feedUrls: string[] = []

        if (pubkey && rssFeedListEvent) {
          // User has an event - use only feeds from that event (even if empty)
          try {
            // Extract URLs from "u" tags
            const urls = rssFeedListEvent.tags
              .filter(tag => tag[0] === 'u' && tag[1])
              .map(tag => tag[1] as string)
              .filter((url): url is string => {
                if (typeof url !== 'string') {
                  logger.warn('[RssFeedList] Invalid RSS feed URL (not a string)', { url, type: typeof url })
                  return false
                }
                const trimmed = url.trim()
                if (trimmed.length === 0) {
                  logger.warn('[RssFeedList] Empty RSS feed URL found')
                  return false
                }
                return true
              })
            
            feedUrls = urls
            if (urls.length > 0) {
              logger.info('[RssFeedList] Loaded RSS feed list from context', { 
                feedCount: urls.length,
                eventId: rssFeedListEvent.id,
                urls
              })
            } else {
              logger.info('[RssFeedList] RSS feed list event exists but is empty - will show empty feed')
            }
          } catch (e) {
            logger.error('[RssFeedList] Failed to parse RSS feed list from tags', { 
              error: e,
              tags: rssFeedListEvent.tags
            })
            // On parse error, treat as empty event (don't use defaults)
            feedUrls = []
          }
        } else if (pubkey) {
          // No event exists - use default feeds for demo
          logger.info('[RssFeedList] No RSS feed list event in context, using default feeds')
          feedUrls = DEFAULT_RSS_FEEDS
          // Trigger background refresh for default feeds when no event exists
          rssFeedService.backgroundRefreshFeeds(feedUrls, abortController.signal).catch(err => {
            if (!(err instanceof DOMException && err.name === 'AbortError')) {
              logger.error('[RssFeedList] Background refresh of default feeds failed', { error: err })
            }
          })
        } else {
          // No pubkey - use default feeds
          feedUrls = DEFAULT_RSS_FEEDS
        }

        // Check if aborted before fetching
        if (abortController.signal.aborted || !isMounted) {
          return
        }

        // Fetch and merge feeds (cache-first: returns cached items immediately, background-refreshes)
        // Show refreshing indicator (background refresh will run in background, or we'll wait if cache is empty)
        if (isMounted) {
          setRefreshing(true)
        }
        
        const fetchedItems = await rssFeedService.fetchMultipleFeeds(feedUrls, abortController.signal)
        
        // Always set items if we got them, even if signal was aborted (abort might happen after fetch completes)
        // Only skip setting items if component unmounted
        if (!isMounted) {
          setRefreshing(false)
          return
        }
        
        // Set items regardless of abort status (abort might have happened after fetch completed)
        if (fetchedItems.length === 0) {
          // No items were successfully fetched, but don't show error if we tried
          // The fetchMultipleFeeds already logs warnings for failed feeds
          setError(null) // Clear any previous error
        }
        
        setItems(fetchedItems)
        
        // Check if aborted after setting items (for cleanup)
        if (abortController.signal.aborted) {
          logger.debug('[RssFeedList] Signal was aborted after fetching, but items were set', {
            itemCount: fetchedItems.length
          })
        }
        
        // Set up a listener for cache updates (background refresh may add new items)
        // Re-check cache after a delay to see if background refresh added items
        const checkForUpdates = async () => {
          if (abortController.signal.aborted || !isMounted) {
            if (isMounted) {
              setRefreshing(false)
            }
            return
          }
          
          try {
            const updatedItems = await rssFeedService.fetchMultipleFeeds(feedUrls, abortController.signal)
            if (!abortController.signal.aborted && isMounted) {
              setRefreshing(false)
              if (updatedItems.length > fetchedItems.length) {
                // New items were added by background refresh
                setItems(updatedItems)
                logger.info('[RssFeedList] Updated items from background refresh', {
                  previousCount: fetchedItems.length,
                  newCount: updatedItems.length
                })
              }
            }
          } catch (err) {
            if (isMounted) {
              setRefreshing(false)
            }
            // Ignore errors in update check
          }
        }
        
        // Check for updates after 5 seconds (background refresh should be done by then)
        setTimeout(checkForUpdates, 5000)
      } catch (err) {
        // Don't handle abort errors - they're expected during cleanup
        if (err instanceof DOMException && err.name === 'AbortError') {
          return
        }

        // Check if still mounted before setting error
        if (!isMounted) {
          return
        }

        logger.error('[RssFeedList] Error loading RSS feeds', { error: err })
        // Don't set error state - fetchMultipleFeeds handles individual feed failures gracefully
        // Only set error if there's a critical issue (like network completely down)
        if (err instanceof TypeError && err.message.includes('Failed to fetch')) {
          // Network error - might be temporary, don't show persistent error
          setError(null)
        } else {
          setError(err instanceof Error ? err.message : t('Failed to load RSS feeds'))
        }
      } finally {
        isLoading = false
        if (timeoutId) {
          clearTimeout(timeoutId)
          timeoutId = null
        }
        // Only update loading state if still mounted
        if (isMounted) {
          setLoading(false)
          // If we had no cached items, background refresh was awaited, so stop refreshing indicator
          if (items.length === 0) {
            setRefreshing(false)
          }
        }
      }
    }

    loadRssFeeds()

    // Listen for RSS feed list updates
    const handleRssFeedListUpdate = (event: CustomEvent) => {
      const detail = event.detail as { pubkey: string; feedUrls: string[]; eventId: string }
      // Only refresh if it's for the current user
      if (detail.pubkey === pubkey && isMounted) {
        logger.info('[RssFeedList] Received RSS feed list update event, refreshing...', { 
          eventId: detail.eventId,
          feedCount: detail.feedUrls.length 
        })
        
        // For manual refresh, show refreshing indicator
        if (detail.eventId === 'manual-refresh' && isMounted) {
          setRefreshing(true)
        }
        
        // For manual refresh, the background refresh is already triggered by the button
        // Just reload to show updated items (background refresh will update cache in the background)
        // For other updates (like event changes), also just reload
        loadRssFeeds(true)
      }
    }

    window.addEventListener('rssFeedListUpdated', handleRssFeedListUpdate as EventListener)

    return () => {
      isMounted = false
      isLoading = false
      if (timeoutId) {
        clearTimeout(timeoutId)
      }
      // Abort any in-flight requests
      abortController.abort()
      window.removeEventListener('rssFeedListUpdated', handleRssFeedListUpdate as EventListener)
    }
  }, [pubkey, rssFeedListEvent, t])

  // Normalize feed URL to prevent duplicates (e.g., with/without trailing slash)
  // This matches the normalization used in rss-feed.service.ts
  const normalizeFeedUrl = (url: string): string => {
    return url.trim().replace(/\/$/, '')
  }

  // Get unique feed URLs and titles from items
  // Normalize URLs to prevent duplicates (e.g., with/without trailing slash)
  const availableFeeds = useMemo(() => {
    const feedMap = new Map<string, { url: string; title: string }>()
    
    items.forEach(item => {
      const normalizedUrl = normalizeFeedUrl(item.feedUrl)
      if (!feedMap.has(normalizedUrl)) {
        feedMap.set(normalizedUrl, { url: normalizedUrl, title: item.feedTitle || item.feedUrl })
      }
    })
    return Array.from(feedMap.values())
  }, [items])

  // Helper function to truncate text
  const truncateText = (text: string, maxLength: number): string => {
    if (text.length <= maxLength) return text
    return text.slice(0, maxLength) + '...'
  }

  // Handle feed selection change
  const handleFeedToggle = (feedUrl: string, checked: boolean) => {
    if (feedUrl === 'all') {
      // If "all" is checked, clear all other selections
      setSelectedFeeds(checked ? ['all'] : [])
    } else {
      // If a specific feed is checked, remove "all" if present
      setSelectedFeeds(prev => {
        const newSelection = checked
          ? [...prev.filter(f => f !== 'all'), feedUrl]
          : prev.filter(f => f !== feedUrl)
        // If nothing is selected, default to "all"
        return newSelection.length === 0 ? ['all'] : newSelection
      })
    }
  }

  // Filter items based on selected filters
  const filteredItems = useMemo(() => {
    let filtered = items

    // Filter by feed
    if (!selectedFeeds.includes('all') && selectedFeeds.length > 0) {
      const normalizedSelectedFeeds = selectedFeeds.map(f => normalizeFeedUrl(f))
      filtered = filtered.filter(item => 
        normalizedSelectedFeeds.includes(normalizeFeedUrl(item.feedUrl))
      )
    }

    // Filter by time
    if (timeFilter !== 'all') {
      const now = Date.now()
      let cutoffTime = 0
      
      switch (timeFilter) {
        case 'hour':
          cutoffTime = now - 60 * 60 * 1000
          break
        case 'day':
          cutoffTime = now - 24 * 60 * 60 * 1000
          break
        case 'week':
          cutoffTime = now - 7 * 24 * 60 * 60 * 1000
          break
        case 'month':
          cutoffTime = now - 30 * 24 * 60 * 60 * 1000
          break
      }
      
      filtered = filtered.filter(item => {
        if (!item.pubDate) return false
        return item.pubDate.getTime() >= cutoffTime
      })
    }

    // Filter by search query
    if (searchQuery.trim()) {
      const query = searchQuery.toLowerCase().trim()
      filtered = filtered.filter(item => {
        const titleMatch = item.title.toLowerCase().includes(query)
        const descMatch = item.description.toLowerCase().includes(query)
        const feedMatch = (item.feedTitle || '').toLowerCase().includes(query)
        return titleMatch || descMatch || feedMatch
      })
    }

    return filtered
  }, [items, selectedFeeds, timeFilter, searchQuery])

  // Reset showCount when filters change
  useEffect(() => {
    setShowCount(25)
  }, [selectedFeeds, timeFilter, searchQuery])

  // Pagination: slice to showCount for display
  const displayedItems = useMemo(() => {
    return filteredItems.slice(0, showCount)
  }, [filteredItems, showCount])

  // IntersectionObserver for infinite scroll
  useEffect(() => {
    if (!bottomRef.current || displayedItems.length >= filteredItems.length) return

    const observer = new IntersectionObserver(
      (entries) => {
        if (entries[0].isIntersecting && displayedItems.length < filteredItems.length) {
          setShowCount((prev) => Math.min(prev + 25, filteredItems.length))
        }
      },
      { root: null, rootMargin: '100px', threshold: 0.1 }
    )

    observer.observe(bottomRef.current)

    return () => {
      observer.disconnect()
    }
  }, [displayedItems.length, filteredItems.length])

  // Get display text for feed selector
  const feedSelectorText = useMemo(() => {
    if (selectedFeeds.includes('all') || selectedFeeds.length === 0) {
      return t('All feeds')
    }
    if (selectedFeeds.length === 1) {
      const feed = availableFeeds.find(f => f.url === selectedFeeds[0])
      return feed ? truncateText(feed.title, 50) : t('All feeds')
    }
    return t('{{count}} feeds', { count: selectedFeeds.length })
  }, [selectedFeeds, availableFeeds, t])

  if (loading) {
    return (
      <div className="flex flex-col items-center justify-center py-12">
        <Loader className="h-8 w-8 animate-spin text-muted-foreground" />
        <p className="mt-4 text-sm text-muted-foreground">{t('Loading RSS feeds...')}</p>
      </div>
    )
  }

  if (error) {
    return (
      <div className="flex flex-col items-center justify-center py-12 px-4">
        <AlertCircle className="h-8 w-8 text-destructive mb-4" />
        <p className="text-sm text-destructive text-center">{error}</p>
      </div>
    )
  }

  if (items.length === 0) {
    return (
      <div className="space-y-4 px-4 py-6">
        <ManualRssUrlAddRow />
        <p className="text-sm text-muted-foreground text-center">{t('No RSS feed items available')}</p>
      </div>
    )
  }

  return (
    <div className="space-y-3">
      {/* Feed Counter Header - Always visible */}
      <div className="sticky top-0 z-10 bg-background border-b px-4 py-1.5">
        <div className="flex items-center justify-between gap-4">
          <div className="flex items-center gap-2">
            <Switch
              id="compact-view"
              checked={isCompactView}
              onCheckedChange={setIsCompactView}
            />
            <Label htmlFor="compact-view" className="text-xs text-muted-foreground cursor-pointer">
              {isCompactView ? t('Compact') : t('Full')}
            </Label>
          </div>
          <p className="text-xs text-muted-foreground">
            {t('Showing {{filtered}} of {{total}} items', { 
              filtered: displayedItems.length, 
              total: filteredItems.length 
            })}
          </p>
        </div>
      </div>

      {/* Filter Bar - Collapsible */}
      {showFilters && (
        <div className="sticky top-[2.5rem] z-10 bg-background border-b px-4 py-2">
          <div className={`flex ${isSmallScreen ? 'flex-col' : 'flex-row'} items-stretch gap-2`}>
            {/* Feed Selector - Multi-select with Popover */}
            <Popover open={feedPopoverOpen} onOpenChange={setFeedPopoverOpen}>
              <PopoverTrigger asChild>
                <Button
                  variant="outline"
                  role="combobox"
                  className="h-8 text-xs md:text-sm md:h-9 flex-shrink-0 w-full md:w-auto justify-between"
                  style={{ minWidth: isSmallScreen ? '100%' : '300px' }}
                >
                  <span className="truncate">{feedSelectorText}</span>
                  <ChevronDown className="ml-2 h-3 w-3 md:h-4 md:w-4 shrink-0 opacity-50" />
                </Button>
              </PopoverTrigger>
              <PopoverContent className={`${isSmallScreen ? 'w-[calc(100vw-2rem)]' : 'w-[calc(100vw-2rem)] max-w-[400px]'} p-0`} align="start">
                <div className="max-h-[300px] overflow-y-auto">
                  <div className="p-2">
                    {/* All feeds option */}
                    <div
                      className="flex items-center space-x-2 p-2 rounded-sm hover:bg-accent cursor-pointer"
                      onClick={() => {
                        const isAllSelected = selectedFeeds.includes('all')
                        handleFeedToggle('all', !isAllSelected)
                      }}
                    >
                      <div className="flex items-center justify-center w-4 h-4 border border-border rounded">
                        {selectedFeeds.includes('all') && <Check className="w-3 h-3" />}
                      </div>
                      <label className="text-sm cursor-pointer flex-1">
                        {t('All feeds')}
                      </label>
                    </div>
                    {/* Individual feed options */}
                    {availableFeeds.map((feed) => {
                      const isChecked = selectedFeeds.includes(feed.url)
                      return (
                        <div
                          key={feed.url}
                          className="flex items-center space-x-2 p-2 rounded-sm hover:bg-accent cursor-pointer"
                          onClick={() => handleFeedToggle(feed.url, !isChecked)}
                        >
                          <div className="flex items-center justify-center w-4 h-4 border border-border rounded">
                            {isChecked && <Check className="w-3 h-3" />}
                          </div>
                          <label className="text-sm cursor-pointer flex-1 truncate" title={feed.title}>
                            {truncateText(feed.title, 50)}
                          </label>
                        </div>
                      )
                    })}
                  </div>
                </div>
              </PopoverContent>
            </Popover>

            {/* Time Filter */}
            <Select value={timeFilter} onValueChange={setTimeFilter}>
              <SelectTrigger className="h-8 text-xs md:text-sm md:h-9 flex-shrink-0 w-full md:w-auto" style={{ minWidth: isSmallScreen ? '100%' : '120px' }}>
                <SelectValue placeholder={t('All time')} />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="all">{t('All time')}</SelectItem>
                <SelectItem value="hour">{t('Last hour')}</SelectItem>
                <SelectItem value="day">{t('Last day')}</SelectItem>
                <SelectItem value="week">{t('Last week')}</SelectItem>
                <SelectItem value="month">{t('Last month')}</SelectItem>
              </SelectContent>
            </Select>

            {/* Search Box */}
            <div className="relative flex-1 min-w-0">
              <Search className="absolute left-2 top-1/2 transform -translate-y-1/2 h-3.5 w-3.5 md:h-4 md:w-4 text-muted-foreground" />
              <Input
                type="text"
                placeholder={t('Search...')}
                value={searchQuery}
                onChange={(e) => setSearchQuery(e.target.value)}
                className="h-8 md:h-9 pl-7 md:pl-8 text-xs md:text-sm w-full"
              />
            </div>
          </div>
        </div>
      )}

      {/* Content */}
      <div className="space-y-4 px-4 py-3">
        <ManualRssUrlAddRow />
        {refreshing && (
          <div className="flex items-center justify-center gap-2 py-2 text-sm text-muted-foreground border-b">
            <Loader className="h-4 w-4 animate-spin" />
            <span>{t('Refreshing feeds...')}</span>
          </div>
        )}
        
        {displayedItems.length === 0 ? (
          <div className="flex flex-col items-center justify-center py-12">
            <p className="text-sm text-muted-foreground">
              {searchQuery || (!selectedFeeds.includes('all') && selectedFeeds.length > 0) || timeFilter !== 'all'
                ? t('No items match your filters')
                : t('No RSS feed items available')}
            </p>
          </div>
        ) : (
          <>
            {displayedItems.map((item) => (
              <RssFeedItem key={`${item.feedUrl}-${item.guid}`} item={item} layout={isCompactView ? 'list' : 'detail'} />
            ))}
            {/* Bottom ref for infinite scroll */}
            {displayedItems.length < filteredItems.length && (
              <div ref={bottomRef} className="flex items-center justify-center py-4">
                <Loader className="h-4 w-4 animate-spin text-muted-foreground" />
              </div>
            )}
          </>
        )}
      </div>
    </div>
  )
}

