'use client'

import { useCallback, useEffect, useRef, useState } from 'react'
import Link from 'next/link'
import type { Route } from 'next'
import { usePathname } from 'next/navigation'
import { trpc } from '@/lib/trpc/client'
import { cn, formatRelativeTime } from '@/lib/utils'
import { Button } from '@/components/ui/button'
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from '@/components/ui/popover'
import { ScrollArea } from '@/components/ui/scroll-area'
import {
  Bell,
  CheckCheck,
  Settings,
  AlertTriangle,
  FileText,
  Files,
  Upload,
  ClipboardList,
  PlayCircle,
  Clock,
  AlertCircle,
  Lock,
  Users,
  TrendingUp,
  Trophy,
  CheckCircle,
  Star,
  GraduationCap,
  Vote,
  Brain,
  Download,
  AlertOctagon,
  RefreshCw,
  CalendarPlus,
  Heart,
  BarChart,
  Award,
  UserPlus,
  UserCheck,
  UserMinus,
  FileCheck,
  Eye,
  MessageSquare,
  MessageCircle,
  Info,
  Calendar,
  Newspaper,
  UserX,
  Lightbulb,
  BookOpen,
  XCircle,
  Edit,
  FileUp,
} from 'lucide-react'

// Icon mapping for notification types
const ICON_MAP: Record<string, React.ComponentType<{ className?: string }>> = {
  Brain,
  AlertTriangle,
  FileText,
  Files,
  Upload,
  ClipboardList,
  PlayCircle,
  Clock,
  AlertCircle,
  Lock,
  Users,
  TrendingUp,
  Trophy,
  CheckCircle,
  Star,
  GraduationCap,
  Vote,
  Download,
  AlertOctagon,
  RefreshCw,
  CalendarPlus,
  Heart,
  BarChart,
  Award,
  UserPlus,
  UserCheck,
  UserMinus,
  FileCheck,
  Eye,
  MessageSquare,
  MessageCircle,
  Info,
  Calendar,
  Newspaper,
  UserX,
  Lightbulb,
  BookOpen,
  XCircle,
  Edit,
  FileUp,
  Bell,
}

// Priority styles
const PRIORITY_STYLES = {
  low: {
    iconBg: 'bg-slate-100 dark:bg-slate-800',
    iconColor: 'text-slate-500',
  },
  normal: {
    iconBg: 'bg-blue-100 dark:bg-blue-900/30',
    iconColor: 'text-blue-600 dark:text-blue-400',
  },
  high: {
    iconBg: 'bg-amber-100 dark:bg-amber-900/30',
    iconColor: 'text-amber-600 dark:text-amber-400',
  },
  urgent: {
    iconBg: 'bg-red-100 dark:bg-red-900/30',
    iconColor: 'text-red-600 dark:text-red-400',
  },
}

type Notification = {
  id: string
  type: string
  priority: string
  icon: string | null
  title: string
  message: string
  linkUrl: string | null
  linkLabel: string | null
  isRead: boolean
  createdAt: Date
}

function NotificationItem({
  notification,
  onRead,
  observeRef,
}: {
  notification: Notification
  onRead: () => void
  observeRef?: (el: HTMLDivElement | null) => void
}) {
  const IconComponent = ICON_MAP[notification.icon || 'Bell'] || Bell
  const priorityStyle =
    PRIORITY_STYLES[notification.priority as keyof typeof PRIORITY_STYLES] ||
    PRIORITY_STYLES.normal

  const content = (
    <div
      ref={observeRef}
      data-notification-id={notification.id}
      className={cn(
        'flex gap-3 p-3 hover:bg-muted/50 transition-colors cursor-pointer',
        !notification.isRead && 'bg-blue-50/50 dark:bg-blue-950/20'
      )}
      onClick={onRead}
    >
      {/* Icon with colored background */}
      <div
        className={cn(
          'shrink-0 w-10 h-10 rounded-full flex items-center justify-center',
          priorityStyle.iconBg
        )}
      >
        <IconComponent className={cn('h-5 w-5', priorityStyle.iconColor)} />
      </div>

      {/* Content */}
      <div className="flex-1 min-w-0">
        <p className={cn('text-sm', !notification.isRead && 'font-medium')}>
          {notification.title}
        </p>
        <p className="text-sm text-muted-foreground line-clamp-2">
          {notification.message}
        </p>
        <div className="flex items-center gap-2 mt-1">
          <span className="text-xs text-muted-foreground">
            {formatRelativeTime(notification.createdAt)}
          </span>
          {notification.linkLabel && (
            <span className="text-xs text-primary font-medium">
              {notification.linkLabel} &rarr;
            </span>
          )}
        </div>
      </div>

      {/* Unread dot */}
      {!notification.isRead && (
        <div className="shrink-0 w-2 h-2 rounded-full bg-primary mt-2" />
      )}
    </div>
  )

  if (notification.linkUrl) {
    return (
      <Link href={notification.linkUrl as Route} className="block">
        {content}
      </Link>
    )
  }

  return content
}

export function NotificationBell() {
  const [open, setOpen] = useState(false)
  const pathname = usePathname()

  // Derive the role-based path prefix from the current route
  const pathPrefix = pathname.startsWith('/admin')
    ? '/admin'
    : pathname.startsWith('/jury')
      ? '/jury'
      : pathname.startsWith('/mentor')
        ? '/mentor'
        : pathname.startsWith('/observer')
          ? '/observer'
          : ''

  const { data: countData } = trpc.notification.getUnreadCount.useQuery(
    undefined,
    {
      refetchInterval: 30000, // Refetch every 30 seconds
    }
  )

  const { data: hasUrgent } = trpc.notification.hasUrgent.useQuery(undefined, {
    refetchInterval: 30000,
  })

  const { data: notificationData, refetch } = trpc.notification.list.useQuery(
    {
      unreadOnly: false,
      limit: 20,
    },
    {
      enabled: open, // Only fetch when popover is open
    }
  )

  const markAsReadMutation = trpc.notification.markAsRead.useMutation({
    onSuccess: () => refetch(),
  })

  const markAllAsReadMutation = trpc.notification.markAllAsRead.useMutation({
    onSuccess: () => refetch(),
  })

  const markBatchAsReadMutation = trpc.notification.markBatchAsRead.useMutation({
    onSuccess: () => refetch(),
  })

  const unreadCount = countData ?? 0
  const notifications = notificationData?.notifications ?? []

  // Track unread notification IDs that have become visible
  const pendingReadIds = useRef<Set<string>>(new Set())
  const flushTimer = useRef<ReturnType<typeof setTimeout> | null>(null)
  const observerRef = useRef<IntersectionObserver | null>(null)
  const itemRefs = useRef<Map<string, HTMLDivElement>>(new Map())

  // Flush pending read IDs in a batch
  const flushPendingReads = useCallback(() => {
    if (pendingReadIds.current.size === 0) return
    const ids = Array.from(pendingReadIds.current)
    pendingReadIds.current.clear()
    markBatchAsReadMutation.mutate({ ids })
  }, [markBatchAsReadMutation])

  // Set up IntersectionObserver when popover opens
  useEffect(() => {
    if (!open) {
      // Flush any remaining on close
      if (flushTimer.current) clearTimeout(flushTimer.current)
      flushPendingReads()
      observerRef.current?.disconnect()
      observerRef.current = null
      return
    }

    observerRef.current = new IntersectionObserver(
      (entries) => {
        for (const entry of entries) {
          if (entry.isIntersecting) {
            const id = (entry.target as HTMLElement).dataset.notificationId
            if (id) {
              // Check if this notification is unread
              const notif = notifications.find((n) => n.id === id)
              if (notif && !notif.isRead) {
                pendingReadIds.current.add(id)
              }
            }
          }
        }
        // Debounce the batch call
        if (pendingReadIds.current.size > 0) {
          if (flushTimer.current) clearTimeout(flushTimer.current)
          flushTimer.current = setTimeout(flushPendingReads, 500)
        }
      },
      { threshold: 0.5 }
    )

    // Observe all currently tracked items
    itemRefs.current.forEach((el) => observerRef.current?.observe(el))

    return () => {
      observerRef.current?.disconnect()
      if (flushTimer.current) clearTimeout(flushTimer.current)
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open, notifications])

  // Ref callback for each notification item
  const getItemRef = useCallback(
    (id: string) => (el: HTMLDivElement | null) => {
      if (el) {
        itemRefs.current.set(id, el)
        observerRef.current?.observe(el)
      } else {
        const prev = itemRefs.current.get(id)
        if (prev) observerRef.current?.unobserve(prev)
        itemRefs.current.delete(id)
      }
    },
    []
  )

  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <Button variant="ghost" size="icon" className="relative">
          <Bell
            className={cn('h-5 w-5', hasUrgent && 'animate-pulse text-red-500')}
          />
          {unreadCount > 0 && (
            <span
              className={cn(
                'absolute -top-1 -right-1 min-w-5 h-5 px-1 rounded-full text-[10px] font-bold text-white flex items-center justify-center',
                hasUrgent ? 'bg-red-500' : 'bg-primary'
              )}
            >
              {unreadCount > 99 ? '99+' : unreadCount}
            </span>
          )}
          <span className="sr-only">Notifications</span>
        </Button>
      </PopoverTrigger>
      <PopoverContent className="w-96 p-0" align="end">
        {/* Header */}
        <div className="flex items-center justify-between p-3 border-b">
          <h3 className="font-semibold">Notifications</h3>
          <div className="flex gap-1">
            {unreadCount > 0 && (
              <Button
                variant="ghost"
                size="sm"
                onClick={() => markAllAsReadMutation.mutate()}
                disabled={markAllAsReadMutation.isPending}
              >
                <CheckCheck className="h-4 w-4 mr-1" />
                Mark all read
              </Button>
            )}
            <Button variant="ghost" size="icon" asChild>
              <Link href={`${pathPrefix}/settings` as Route}>
                <Settings className="h-4 w-4" />
                <span className="sr-only">Notification settings</span>
              </Link>
            </Button>
          </div>
        </div>

        {/* Notification list */}
        <ScrollArea className="h-[400px]">
          <div className="divide-y">
            {notifications.map((notification) => (
              <NotificationItem
                key={notification.id}
                notification={notification}
                observeRef={!notification.isRead ? getItemRef(notification.id) : undefined}
                onRead={() => {
                  if (!notification.isRead) {
                    markAsReadMutation.mutate({ id: notification.id })
                  }
                }}
              />
            ))}
            {notifications.length === 0 && (
              <div className="p-8 text-center">
                <Bell className="h-10 w-10 mx-auto text-muted-foreground/30" />
                <p className="mt-2 text-muted-foreground">
                  No notifications yet
                </p>
              </div>
            )}
          </div>
        </ScrollArea>

        {/* Footer */}
        {notifications.length > 0 && (
          <div className="p-2 border-t bg-muted/30">
            <Button variant="ghost" className="w-full" asChild>
              <Link href={`${pathPrefix}/notifications` as Route}>View all notifications</Link>
            </Button>
          </div>
        )}
      </PopoverContent>
    </Popover>
  )
}
