import { router } from '@inertiajs/react';
import { Bell, Check, CheckCheck, Loader2, Trash2 } from 'lucide-react';
import { useCallback, useEffect, useRef, useState } from 'react';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import {
    DropdownMenu,
    DropdownMenuContent,
    DropdownMenuSeparator,
    DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';

interface Notification {
    id: number;
    title: string;
    body: string | null;
    url: string | null;
    is_read: boolean;
    created_at: string;
}

interface PaginatedResponse {
    data: Notification[];
    current_page: number;
    last_page: number;
    next_page_url: string | null;
}

export function NotificationBell() {
    const [notifications, setNotifications] = useState<Notification[]>([]);
    const [unreadCount, setUnreadCount] = useState(0);
    const [isOpen, setIsOpen] = useState(false);
    const [currentPage, setCurrentPage] = useState(1);
    const [lastPage, setLastPage] = useState(1);
    const [loadingMore, setLoadingMore] = useState(false);
    const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
    const mountedRef = useRef(true);
    const sentinelRef = useRef<HTMLDivElement | null>(null);

    useEffect(() => {
        mountedRef.current = true;

        return () => {
            mountedRef.current = false;
        };
    }, []);

    const fetchUnreadCount = useCallback(async () => {
        try {
            const response = await fetch('/api/notifications/unread-count', {
                headers: {
                    'X-Requested-With': 'XMLHttpRequest',
                },
            });

            if (response.ok && mountedRef.current) {
                const data = await response.json();
                setUnreadCount(data.count);
            }
        } catch {
            // Silently fail
        }
    }, []);

    const fetchNotifications = useCallback(async (page: number = 1) => {
        try {
            const response = await fetch(`/api/notifications?page=${page}`, {
                headers: {
                    'X-Requested-With': 'XMLHttpRequest',
                },
            });

            if (response.ok && mountedRef.current) {
                const data: PaginatedResponse = await response.json();

                if (page === 1) {
                    setNotifications(data.data);
                } else {
                    setNotifications((prev) => [...prev, ...data.data]);
                }

                setCurrentPage(data.current_page);
                setLastPage(data.last_page);
            }
        } catch {
            // Silently fail
        }
    }, []);

    const fetchNextPage = useCallback(async () => {
        if (loadingMore || currentPage >= lastPage) {
return;
}

        setLoadingMore(true);
        await fetchNotifications(currentPage + 1);
        setLoadingMore(false);
    }, [loadingMore, currentPage, lastPage, fetchNotifications]);

    const markAsRead = useCallback(async (id: number) => {
        try {
            await fetch(`/api/notifications/${id}/read`, {
                method: 'PATCH',
                headers: {
                    'X-Requested-With': 'XMLHttpRequest',
                },
            });

            setNotifications((prev) =>
                prev.map((n) => (n.id === id ? { ...n, is_read: true } : n)),
            );
            setUnreadCount((prev) => Math.max(0, prev - 1));
        } catch {
            // Silently fail
        }
    }, []);

    const deleteNotification = useCallback(async (id: number) => {
        try {
            await fetch(`/api/notifications/${id}`, {
                method: 'DELETE',
                headers: {
                    'X-Requested-With': 'XMLHttpRequest',
                },
            });

            setNotifications((prev) => prev.filter((n) => n.id !== id));
            setUnreadCount((prev) => Math.max(0, prev - 1));
        } catch {
            // Silently fail
        }
    }, []);

    const markAllAsRead = useCallback(async () => {
        try {
            await fetch('/api/notifications/read-all', {
                method: 'PATCH',
                headers: {
                    'X-Requested-With': 'XMLHttpRequest',
                },
            });

            setNotifications((prev) =>
                prev.map((n) => ({ ...n, is_read: true })),
            );
            setUnreadCount(0);
        } catch {
            // Silently fail
        }
    }, []);

    const deleteAll = useCallback(async () => {
        try {
            await fetch('/api/notifications', {
                method: 'DELETE',
                headers: {
                    'X-Requested-With': 'XMLHttpRequest',
                },
            });

            setNotifications([]);
            setUnreadCount(0);
        } catch {
            // Silently fail
        }
    }, []);

    useEffect(() => {
        // eslint-disable-next-line react-hooks/set-state-in-effect -- initial data fetch is safe
        void fetchUnreadCount();
        intervalRef.current = setInterval(() => {
            void fetchUnreadCount();
        }, 30000);

        return () => {
            if (intervalRef.current) {
                clearInterval(intervalRef.current);
            }
        };
    }, [fetchUnreadCount]);

    useEffect(() => {
        if (isOpen) {
            // eslint-disable-next-line react-hooks/set-state-in-effect -- reset pagination on open is safe
            setCurrentPage(1);
            setLastPage(1);
            void fetchNotifications(1);
        } else {
            setNotifications([]);
        }
    }, [isOpen, fetchNotifications]);

    useEffect(() => {
        if (!isOpen || !sentinelRef.current) {
return;
}

        const observer = new IntersectionObserver(
            (entries) => {
                if (entries[0].isIntersecting && !loadingMore && currentPage < lastPage) {
                    void fetchNextPage();
                }
            },
            { rootMargin: '100px' },
        );

        observer.observe(sentinelRef.current);

        return () => observer.disconnect();
    }, [isOpen, loadingMore, currentPage, lastPage, fetchNextPage]);

    return (
        <DropdownMenu onOpenChange={setIsOpen}>
            <DropdownMenuTrigger asChild>
                <Button
                    variant="ghost"
                    size="icon"
                    className="relative h-9 w-9"
                >
                    <Bell className="h-4 w-4" />
                    {unreadCount > 0 && (
                        <Badge
                            variant="destructive"
                            className="absolute -top-1 -right-1 flex h-5 min-w-5 items-center justify-center rounded-full px-1 text-xs"
                        >
                            {unreadCount > 99 ? '99+' : unreadCount}
                        </Badge>
                    )}
                    <span className="sr-only">Notifikasi</span>
                </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="end" className="max-h-[350px] w-80 overflow-y-auto">
                <div className="flex items-center justify-between border-b px-4 py-2">
                    <span className="text-sm font-semibold">Notifikasi</span>
                    <div className="flex items-center gap-1">
                        {unreadCount > 0 && (
                            <Button
                                variant="ghost"
                                size="icon"
                                className="h-6 w-6"
                                title="Tandai semua sudah dibaca"
                                onClick={() => {
                                    void markAllAsRead();
                                }}
                            >
                                <CheckCheck className="h-3.5 w-3.5" />
                            </Button>
                        )}
                        {notifications.length > 0 && (
                            <Button
                                variant="ghost"
                                size="icon"
                                className="h-6 w-6 text-destructive hover:text-destructive"
                                title="Hapus semua notifikasi"
                                onClick={() => {
                                    void deleteAll();
                                }}
                            >
                                <Trash2 className="h-3.5 w-3.5" />
                            </Button>
                        )}
                    </div>
                </div>
                {notifications.length === 0 ? (
                    <div className="px-4 py-6 text-center text-sm text-muted-foreground">
                        Tidak ada notifikasi
                    </div>
                ) : (
                    <>
                        {notifications.map((notification) => (
                            <div key={notification.id}>
                                <div
                                    className={`flex items-start gap-2 px-4 py-3 ${
                                        !notification.is_read
                                            ? 'border-l-2 border-l-primary bg-primary/5'
                                            : 'opacity-60'
                                    }`}
                                >
                                    <div
                                        className="min-w-0 flex-1 cursor-pointer"
                                        onClick={() => {
                                            if (notification.url) {
                                                if (!notification.is_read) {
                                                    void markAsRead(notification.id);
                                                }

                                                router.visit(notification.url);
                                            }
                                        }}
                                    >
                                        <span
                                            className={`text-sm ${
                                                !notification.is_read
                                                    ? 'font-semibold'
                                                    : 'font-medium'
                                            }`}
                                        >
                                            {notification.title}
                                        </span>
                                        {notification.body && (
                                            <span className="mt-0.5 line-clamp-2 block text-xs text-muted-foreground">
                                                {notification.body}
                                            </span>
                                        )}
                                        <span className="mt-0.5 block text-xs text-muted-foreground">
                                            {new Date(
                                                notification.created_at,
                                            ).toLocaleDateString('id-ID', {
                                                day: 'numeric',
                                                month: 'short',
                                                hour: '2-digit',
                                                minute: '2-digit',
                                            })}
                                        </span>
                                    </div>
                                    <div className="flex shrink-0 flex-col gap-1 pt-0.5">
                                        {!notification.is_read && (
                                            <Button
                                                variant="ghost"
                                                size="icon"
                                                className="h-6 w-6"
                                                title="Tandai sudah dibaca"
                                                onClick={() => {
                                                    void markAsRead(
                                                        notification.id,
                                                    );
                                                }}
                                            >
                                                <Check className="h-3 w-3" />
                                            </Button>
                                        )}
                                        <Button
                                            variant="ghost"
                                            size="icon"
                                            className="h-6 w-6 text-destructive hover:text-destructive"
                                            title="Hapus"
                                            onClick={() => {
                                                void deleteNotification(
                                                    notification.id,
                                                );
                                            }}
                                        >
                                            <Trash2 className="h-3 w-3" />
                                        </Button>
                                    </div>
                                </div>
                                <DropdownMenuSeparator />
                            </div>
                        ))}

                        {/* Sentinel for infinite scroll */}
                        <div ref={sentinelRef} className="px-4 py-2">
                            {loadingMore && (
                                <div className="flex items-center justify-center gap-2 text-xs text-muted-foreground">
                                    <Loader2 className="h-3 w-3 animate-spin" />
                                    <span>Memuat lainnya...</span>
                                </div>
                            )}
                            {!loadingMore && currentPage >= lastPage && notifications.length > 0 && (
                                <p className="text-center text-xs text-muted-foreground">
                                    Semua notifikasi sudah dimuat
                                </p>
                            )}
                        </div>
                    </>
                )}
            </DropdownMenuContent>
        </DropdownMenu>
    );
}
