import { router } from '@inertiajs/react';
import { Bell, CheckCheck } from 'lucide-react';
import { useState } from 'react';

import { Button } from '@/components/ui/button';
import {
    DropdownMenu,
    DropdownMenuContent,
    DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { useNotifications } from '@/hooks/use-notifications';
import { cn, formatRelativeTime } from '@/lib/utils';
import { open as openNotification } from '@/routes/notifications';
import type { AppNotification } from '@/types/notification';

/**
 * Batas atas angka yang ditampilkan di badge; di atas ini tampil "9+".
 */
const BADGE_MAX = 9;

/**
 * Sisa jarak scroll (px) ke dasar daftar yang memicu pemuatan halaman berikutnya.
 */
const LOAD_MORE_THRESHOLD_PX = 64;

/**
 * Tombol lonceng notifikasi untuk header. Menampilkan badge jumlah belum dibaca
 * dan membuka dropdown berisi daftar notifikasi terbaru. Daftar di-fetch saat
 * dropdown dibuka agar selalu fresh dan hemat.
 */
export function NotificationBell() {
    const {
        unreadCount,
        notifications,
        isLoading,
        hasMore,
        refresh,
        loadMore,
        markAllAsRead,
    } = useNotifications();
    const [open, setOpen] = useState(false);

    const handleOpenChange = (nextOpen: boolean) => {
        setOpen(nextOpen);

        if (nextOpen) {
            void refresh();
        }
    };

    // Klik notifikasi: server yang menandainya dibaca sekaligus mengarahkan ke
    // halaman task terkait (project atau divisi) dengan deep-link `?task=<id>`,
    // jadi badge unread pada halaman tujuan selalu sinkron.
    const handleSelect = (notification: AppNotification) => {
        setOpen(false);
        router.visit(openNotification(notification.id).url);
    };

    // Muat halaman berikutnya begitu daftar discroll mendekati dasar.
    const handleScroll = (event: React.UIEvent<HTMLDivElement>) => {
        const { scrollHeight, scrollTop, clientHeight } = event.currentTarget;

        if (scrollHeight - scrollTop - clientHeight < LOAD_MORE_THRESHOLD_PX) {
            void loadMore();
        }
    };

    const badgeLabel = unreadCount > BADGE_MAX ? `${BADGE_MAX}+` : unreadCount;

    return (
        <DropdownMenu open={open} onOpenChange={handleOpenChange}>
            <DropdownMenuTrigger asChild>
                <Button
                    variant="ghost"
                    size="icon"
                    className="relative"
                    aria-label={
                        unreadCount > 0
                            ? `Notifications, ${unreadCount} unread`
                            : 'Notifications'
                    }
                >
                    <Bell className="size-5" />
                    {unreadCount > 0 && (
                        <span
                            className="absolute -top-0.5 -right-0.5 flex min-w-4 items-center justify-center rounded-full bg-destructive px-1 text-[10px] leading-none font-semibold text-white"
                            aria-hidden="true"
                        >
                            {badgeLabel}
                        </span>
                    )}
                </Button>
            </DropdownMenuTrigger>

            <DropdownMenuContent
                align="end"
                sideOffset={8}
                className="w-120 max-w-[calc(100vw-2rem)] p-0"
            >
                <div className="flex items-center justify-between border-b px-3 py-2">
                    <span className="text-sm font-semibold">Notifications</span>
                    {unreadCount > 0 && (
                        <button
                            type="button"
                            onClick={() => void markAllAsRead()}
                            className="flex cursor-pointer items-center gap-1 text-xs text-muted-foreground transition-colors hover:text-foreground"
                        >
                            <CheckCheck className="size-3.5" />
                            Mark all as read
                        </button>
                    )}
                </div>

                <div
                    className="max-h-128 overflow-y-auto"
                    onScroll={handleScroll}
                >
                    {isLoading && notifications.length === 0 ? (
                        <p className="px-3 py-8 text-center text-sm text-muted-foreground">
                            Loading notifications…
                        </p>
                    ) : notifications.length === 0 ? (
                        <p className="px-3 py-8 text-center text-sm text-muted-foreground">
                            No notifications yet.
                        </p>
                    ) : (
                        <>
                            <ul>
                                {notifications.map((notification) => (
                                    <NotificationItem
                                        key={notification.id}
                                        notification={notification}
                                        onSelect={handleSelect}
                                    />
                                ))}
                            </ul>
                            {hasMore && (
                                <p className="px-3 py-3 text-center text-xs text-muted-foreground">
                                    Loading more…
                                </p>
                            )}
                        </>
                    )}
                </div>
            </DropdownMenuContent>
        </DropdownMenu>
    );
}

/**
 * Satu baris notifikasi di dalam dropdown. Mengklik notifikasi menandainya
 * sebagai sudah dibaca dan membuka detail task terkait.
 */
function NotificationItem({
    notification,
    onSelect,
}: {
    notification: AppNotification;
    onSelect: (notification: AppNotification) => void;
}) {
    return (
        <li>
            <button
                type="button"
                onClick={() => onSelect(notification)}
                className={cn(
                    'flex w-full cursor-pointer gap-2 border-b px-3 py-2.5 text-left transition-colors last:border-b-0 hover:bg-accent',
                    !notification.is_read && 'bg-accent/40',
                )}
            >
                {/* Titik penanda belum dibaca */}
                <span
                    className={cn(
                        'mt-1.5 size-2 shrink-0 rounded-full',
                        notification.is_read
                            ? 'bg-transparent'
                            : 'bg-destructive',
                    )}
                    aria-hidden="true"
                />
                <span className="min-w-0 flex-1">
                    <span className="block truncate text-sm font-medium">
                        {notification.title}
                    </span>
                    <span className="mt-0.5 block text-xs text-muted-foreground">
                        {notification.body}
                    </span>
                    <span className="mt-1 block text-[11px] text-muted-foreground/70">
                        {formatRelativeTime(notification.created_at)}
                    </span>
                </span>
            </button>
        </li>
    );
}
