import { type ReactNode, useEffect, useRef, useState, useCallback } from 'react'
import { X as XIcon, AlertTriangle, Play, Loader } from 'lucide-react'
import styles from './EventFeed.module.css'
import { ButtonGroup } from '../../primitives/ButtonGroup/ButtonGroup'
import type { ButtonGroupItem } from '../../primitives/ButtonGroup/ButtonGroup'

export interface FeedEvent {
  id: string
  severity: 'error' | 'warning' | 'success' | 'running'
  message: string | ReactNode
  /** Plain-text version of message for search filtering (required when message is ReactNode) */
  searchText?: string
  icon?: ReactNode
  timestamp: Date
}

type SeverityFilter = 'error' | 'warning' | 'success' | 'running'

interface EventFeedProps {
  events: FeedEvent[]
  maxItems?: number
  className?: string
}

function formatRelativeTime(date: Date): string {
  const now = Date.now()
  const diff = now - date.getTime()
  if (diff < 1000) return 'just now'
  if (diff < 60_000) return `${Math.floor(diff / 1000)}s ago`
  if (diff < 3_600_000) return `${Math.floor(diff / 60_000)}m ago`
  if (diff < 86_400_000) return `${Math.floor(diff / 3_600_000)}h ago`
  return `${Math.floor(diff / 86_400_000)}d ago`
}

function formatAbsoluteTime(date: Date): string {
  const day = date.getDate()
  const months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
  const month = months[date.getMonth()]
  const year = date.getFullYear()
  const h = String(date.getHours()).padStart(2, '0')
  const m = String(date.getMinutes()).padStart(2, '0')
  return `${day} ${month} ${year}, ${h}:${m}`
}

function getSearchableText(event: FeedEvent): string {
  if (event.searchText) return event.searchText
  if (typeof event.message === 'string') return event.message
  return ''
}

const DEFAULT_ICONS: Record<SeverityFilter, ReactNode> = {
  error: <XIcon size={14} />,
  warning: <AlertTriangle size={14} />,
  success: <Play size={14} />,
  running: <Loader size={14} />,
}

const SEVERITY_COLORS: Record<SeverityFilter, string> = {
  error: 'var(--error)',
  warning: 'var(--warning)',
  success: 'var(--success)',
  running: 'var(--running)',
}

const SEVERITY_LABELS: Record<SeverityFilter, string> = {
  error: 'Error',
  warning: 'Warning',
  success: 'Success',
  running: 'Info',
}

export function EventFeed({ events, maxItems = 200, className }: EventFeedProps) {
  const scrollRef = useRef<HTMLDivElement>(null)
  const [isPaused, setIsPaused] = useState(false)
  const [activeFilters, setActiveFilters] = useState<Set<SeverityFilter>>(new Set())
  const [search, setSearch] = useState('')

  const searchLower = search.toLowerCase()

  const displayed = events
    .slice(-maxItems)
    .filter((e) => activeFilters.size === 0 || activeFilters.has(e.severity))
    .filter((e) => !searchLower || getSearchableText(e).toLowerCase().includes(searchLower))

  // Auto-scroll to top (newest entries are at top in desc sort)
  const scrollToTop = useCallback(() => {
    const el = scrollRef.current
    if (el) {
      el.scrollTop = 0
    }
  }, [])

  useEffect(() => {
    if (!isPaused) {
      scrollToTop()
    }
  }, [events, isPaused, scrollToTop])

  function handleScroll() {
    const el = scrollRef.current
    if (!el) return
    const atTop = el.scrollTop < 8
    setIsPaused(!atTop)
  }

  function toggleFilter(severity: SeverityFilter) {
    setActiveFilters((prev) => {
      const next = new Set(prev)
      if (next.has(severity)) {
        next.delete(severity)
      } else {
        next.add(severity)
      }
      return next
    })
  }

  const allSeverities: SeverityFilter[] = ['error', 'warning', 'success', 'running']

  return (
    <div className={`${styles.feed} ${className ?? ''}`}>
      {/* Search + filter bar */}
      <div className={styles.toolbar}>
        <div className={styles.searchWrap}>
          <input
            type="text"
            className={styles.searchInput}
            placeholder="Search events…"
            value={search}
            onChange={(e) => setSearch(e.target.value)}
            aria-label="Search events"
          />
          {search && (
            <button
              type="button"
              className={styles.searchClear}
              onClick={() => setSearch('')}
              aria-label="Clear search"
            >
              <XIcon size={12} />
            </button>
          )}
        </div>
        <div className={styles.filters}>
          <ButtonGroup
            items={allSeverities.map((sev): ButtonGroupItem => ({
              value: sev,
              label: SEVERITY_LABELS[sev],
              color: SEVERITY_COLORS[sev],
            }))}
            value={activeFilters as Set<string>}
            onChange={(next) => setActiveFilters(next as Set<SeverityFilter>)}
          />
          {activeFilters.size > 0 && (
            <button
              className={styles.clearBtn}
              onClick={() => setActiveFilters(new Set())}
            >
              Clear
            </button>
          )}
        </div>
      </div>

      {/* Event list */}
      <div
        ref={scrollRef}
        className={styles.list}
        onScroll={handleScroll}
        aria-live="polite"
        aria-label="Event feed"
      >
        {displayed.length === 0 ? (
          <div className={styles.empty}>
            {search ? 'No matching events' : 'No events'}
          </div>
        ) : (
          displayed.map((event) => (
            <div key={event.id} className={styles.item}>
              <div className={`${styles.icon} ${styles[`icon_${event.severity}`]}`}>
                {event.icon ?? DEFAULT_ICONS[event.severity]}
              </div>
              <div className={styles.body}>
                <div className={styles.message}>{event.message}</div>
                <div className={styles.time}>
                  {formatRelativeTime(event.timestamp)} &middot; {formatAbsoluteTime(event.timestamp)}
                </div>
              </div>
            </div>
          ))
        )}
      </div>

      {/* Pause indicator */}
      {isPaused && (
        <button
          className={styles.resumeBtn}
          onClick={() => {
            setIsPaused(false)
            scrollToTop()
          }}
        >
          &uarr; Scroll to latest
        </button>
      )}
    </div>
  )
}
