"use client";

import * as React from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useMutation, useQuery } from "convex/react";
import { toast } from "sonner";
import { Bell, CheckCheck, Inbox } from "lucide-react";
import { api } from "../../../convex/_generated/api";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/primitives";
import { relativeTime } from "@/lib/dates";
import { NotificationIcon } from "@/components/notifications/notification-item";

export interface NotificationDto {
  id: string;
  type: string;
  title: string;
  body: string;
  priority: string;
  href: string | null;
  readAt: number | null;
  at: number;
}

/**
 * Reactive notification bell: subscribes to the signed-in worker's inbox, so a
 * row inserted by any Convex mutation appears instantly on every device. New
 * arrivals ring the bell, pop the badge and surface a toast with a shortcut.
 */
export function NotificationsBell({ initialUnread }: { initialUnread: number }) {
  const [open, setOpen] = React.useState(false);
  const [ring, setRing] = React.useState(false);
  const router = useRouter();
  const data = useQuery(api.settings.myNotifications, { limit: 8 });
  const markRead = useMutation(api.settings.markRead);
  const unread = data?.unread ?? initialUnread;
  const items = (data?.items as NotificationDto[] | undefined) ?? null;
  const prevUnread = React.useRef(unread);
  const seen = React.useRef<Set<string> | null>(null);

  React.useEffect(() => {
    if (unread > prevUnread.current) {
      setRing(true);
      if ("vibrate" in navigator) navigator.vibrate?.(10);
      const t = setTimeout(() => setRing(false), 950);
      prevUnread.current = unread;
      return () => clearTimeout(t);
    }
    prevUnread.current = unread;
  }, [unread]);

  // Toast for notifications that arrive while the app is open (never on first load).
  React.useEffect(() => {
    if (!items) return;
    if (!seen.current) {
      seen.current = new Set(items.map((n) => n.id));
      return;
    }
    const fresh = items.filter((n) => !seen.current!.has(n.id) && !n.readAt).slice(0, 3);
    for (const n of items) seen.current.add(n.id);
    for (const n of fresh) {
      toast(n.title, {
        description: n.body,
        icon: <NotificationIcon type={n.type} priority={n.priority} className="size-7 [&_svg]:size-3.5" />,
        action: n.href ? { label: "Open", onClick: () => router.push(n.href!) } : undefined,
      });
    }
  }, [items, router]);

  async function markAll() {
    await markRead({});
    router.refresh();
  }
  async function markOne(id: string) {
    await markRead({ ids: [id as never] });
  }

  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <Button variant="ghost" size="icon" className="relative data-[state=open]:bg-surface-2 data-[state=open]:text-fg" aria-label={`Notifications${unread ? `, ${unread} unread` : ""}`}>
          <Bell className={cn("origin-top-center transition-transform", ring && "animate-bell-ring")} />
          {unread > 0 ? (
            <span key={unread} className="absolute right-1.5 top-1.5 flex size-4 items-center justify-center rounded-full bg-negative-500 text-[9px] font-bold text-white ring-2 ring-bg animate-badge-pop">
              {unread > 9 ? "9+" : unread}
            </span>
          ) : null}
        </Button>
      </PopoverTrigger>
      <PopoverContent align="end" className="w-[calc(100vw-1.5rem)] max-w-sm overflow-hidden p-0">
        <div className="flex items-center justify-between border-b border-border px-4 py-3">
          <p className="flex items-center gap-2 text-sm font-semibold">
            Notifications
            <span className="live-dot" aria-label="Live" />
          </p>
          <Button variant="ghost" size="xs" onClick={markAll} disabled={!unread}>
            <CheckCheck /> Mark all read
          </Button>
        </div>
        <ul className="stagger-fast max-h-[60vh] overflow-y-auto scrollbar-thin">
          {!items ? (
            <li className="space-y-3 p-4">
              {[0, 1, 2].map((i) => (
                <div key={i} className="skeleton h-10" />
              ))}
            </li>
          ) : items.length ? (
            items.map((n) => (
              <li key={n.id} className={cn("border-b border-border transition-colors duration-500 last:border-0", !n.readAt && "bg-primary/[0.04]")}>
                <Link
                  href={n.href ?? "/notifications"}
                  onClick={() => {
                    if (!n.readAt) void markOne(n.id);
                    setOpen(false);
                  }}
                  className="group flex gap-3 px-4 py-3 transition-colors hover:bg-surface-2"
                >
                  <NotificationIcon type={n.type} priority={n.priority} className="transition-transform duration-300 [transition-timing-function:var(--ease-spring)] group-hover:scale-110" />
                  <div className="min-w-0 flex-1">
                    <p className={cn("text-sm leading-snug", !n.readAt ? "font-semibold text-fg" : "text-fg")}>{n.title}</p>
                    <p className="mt-0.5 line-clamp-2 text-xs text-fg-muted">{n.body}</p>
                    <p className="mt-1 text-2xs text-fg-subtle">{relativeTime(new Date(n.at))}</p>
                  </div>
                  {!n.readAt ? <span className="mt-2 size-2 shrink-0 rounded-full bg-primary animate-pulse-soft" /> : null}
                </Link>
              </li>
            ))
          ) : (
            <li className="flex flex-col items-center px-4 py-10 text-center text-sm text-fg-muted">
              <span className="mb-2 flex size-10 items-center justify-center rounded-full bg-surface-2 text-fg-subtle animate-float">
                <Inbox className="size-5" />
              </span>
              You&apos;re all caught up.
            </li>
          )}
        </ul>
        <div className="border-t border-border p-2">
          <Button variant="ghost" size="sm" className="w-full" asChild>
            <Link href="/notifications" onClick={() => setOpen(false)}>
              View all notifications
            </Link>
          </Button>
        </div>
      </PopoverContent>
    </Popover>
  );
}
