'use client';

import Link from 'next/link';
import { Bell } from 'lucide-react';
import { toast } from 'sonner';
import { useConvexAuth, useMutation, useQuery } from 'convex/react';

import { api } from '@spoon/backend/convex/_generated/api.js';
import type { Id } from '@spoon/backend/convex/_generated/dataModel.js';
import {
  Button,
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from '@spoon/ui';

const RELATIVE_UNITS: [Intl.RelativeTimeFormatUnit, number][] = [
  ['year', 365 * 24 * 60 * 60 * 1000],
  ['month', 30 * 24 * 60 * 60 * 1000],
  ['day', 24 * 60 * 60 * 1000],
  ['hour', 60 * 60 * 1000],
  ['minute', 60 * 1000],
];

const relativeFormatter = new Intl.RelativeTimeFormat(undefined, {
  numeric: 'auto',
});

const formatRelativeTime = (timestamp: number): string => {
  const delta = timestamp - Date.now();
  const magnitude = Math.abs(delta);
  for (const [unit, ms] of RELATIVE_UNITS) {
    if (magnitude >= ms) {
      return relativeFormatter.format(Math.round(delta / ms), unit);
    }
  }
  return 'just now';
};

export const NotificationBell = () => {
  const { isAuthenticated } = useConvexAuth();
  const unreadCount = useQuery(
    api.notifications.unreadCount,
    isAuthenticated ? {} : 'skip',
  );
  const notifications = useQuery(
    api.notifications.listMine,
    isAuthenticated ? { limit: 10 } : 'skip',
  );
  const markRead = useMutation(api.notifications.markRead);
  const markAllRead = useMutation(api.notifications.markAllRead);

  if (!isAuthenticated) {
    return null;
  }

  const count = unreadCount ?? 0;
  const badgeLabel = count > 9 ? '9+' : String(count);
  const items = notifications ?? [];

  // Fire-and-forget: never block navigation on the read write, but surface a
  // toast if it fails so we don't silently assume success.
  const handleMarkRead = async (notificationId: Id<'notifications'>) => {
    try {
      await markRead({ notificationId });
    } catch {
      toast.error('Could not mark the notification as read.');
    }
  };

  const handleMarkAllRead = async () => {
    try {
      await markAllRead({});
    } catch {
      toast.error('Could not mark notifications as read.');
    }
  };

  return (
    <DropdownMenu>
      <DropdownMenuTrigger asChild>
        <Button
          variant='ghost'
          size='sm'
          className='relative'
          aria-label='Notifications'
        >
          <Bell className='h-5 w-5' />
          {count > 0 && (
            <span className='bg-primary text-primary-foreground absolute -top-0.5 -right-0.5 flex h-4 min-w-4 items-center justify-center rounded-full px-1 text-[10px] leading-none font-semibold'>
              {badgeLabel}
            </span>
          )}
        </Button>
      </DropdownMenuTrigger>
      <DropdownMenuContent align='end' className='w-80'>
        <div className='flex items-center justify-between gap-2 px-2 py-1.5'>
          <DropdownMenuLabel className='p-0'>Notifications</DropdownMenuLabel>
          {count > 0 && (
            <button
              type='button'
              onClick={() => void handleMarkAllRead()}
              className='text-muted-foreground hover:text-foreground cursor-pointer text-xs'
            >
              Mark all read
            </button>
          )}
        </div>
        <DropdownMenuSeparator />
        {items.length === 0 ? (
          <p className='text-muted-foreground px-2 py-6 text-center text-sm'>
            No notifications yet.
          </p>
        ) : (
          items.map((notification) => (
            <DropdownMenuItem key={notification._id} asChild>
              <Link
                href={notification.link ?? '#'}
                onClick={() => void handleMarkRead(notification._id)}
                className='flex w-full cursor-pointer flex-col items-start gap-0.5'
              >
                <span className='flex w-full items-center gap-2'>
                  <span className='flex-1 truncate text-sm font-medium'>
                    {notification.title}
                  </span>
                  {notification.readAt === undefined && (
                    <span
                      className='bg-primary size-2 shrink-0 rounded-full'
                      aria-hidden
                    />
                  )}
                </span>
                <span className='text-muted-foreground line-clamp-2 text-xs'>
                  {notification.body}
                </span>
                <span className='text-muted-foreground text-[11px]'>
                  {formatRelativeTime(notification.createdAt)}
                </span>
              </Link>
            </DropdownMenuItem>
          ))
        )}
      </DropdownMenuContent>
    </DropdownMenu>
  );
};
