import { useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import {
    Archive,
    AtSign,
    Bell,
    BellOff,
    Check,
    CheckCheck,
    Loader2,
    Mail,
    MessageSquare,
    Shield,
} from "lucide-react";
import { notificationList, notificationMarkRead, notificationMarkAllRead, notificationArchive } from "@/client";
import type { NotificationResponse } from "@/client";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import {getApiErrorMessage} from '@/lib/api-error';

type Filter = "all" | "unread" | "archived";

const NOTIFICATION_TYPE_CONFIG: Record<
    string,
    { label: string; icon: React.ReactNode; color: string }
> = {
    mention: { label: "Mention", icon: <AtSign className="h-3.5 w-3.5" />, color: "bg-blue-500/10 text-blue-600 border-blue-500/20" },
    invitation: { label: "Invitation", icon: <Mail className="h-3.5 w-3.5" />, color: "bg-purple-500/10 text-purple-600 border-purple-500/20" },
    role_change: { label: "Role Change", icon: <Shield className="h-3.5 w-3.5" />, color: "bg-orange-500/10 text-orange-600 border-orange-500/20" },
    room_created: { label: "Room Created", icon: <MessageSquare className="h-3.5 w-3.5" />, color: "bg-green-500/10 text-green-600 border-green-500/20" },
    room_deleted: { label: "Room Deleted", icon: <MessageSquare className="h-3.5 w-3.5" />, color: "bg-red-500/10 text-red-600 border-red-500/20" },
    system_announcement: { label: "Announcement", icon: <Bell className="h-3.5 w-3.5" />, color: "bg-yellow-500/10 text-yellow-700 border-yellow-500/20" },
};

function formatTime(dateStr: string): string {
    const d = new Date(dateStr);
    const now = new Date();
    const diff = now.getTime() - d.getTime();
    const minutes = Math.floor(diff / 60000);
    if (minutes < 1) return "just now";
    if (minutes < 60) return `${minutes}m ago`;
    const hours = Math.floor(minutes / 60);
    if (hours < 24) return `${hours}h ago`;
    const days = Math.floor(hours / 24);
    if (days < 7) return `${days}d ago`;
    return d.toLocaleDateString();
}

function NotificationItem({
    n,
    onMarkRead,
    onArchive,
}: {
    n: NotificationResponse;
    onMarkRead: (id: string) => void;
    onArchive: (id: string) => void;
}) {
    const config = NOTIFICATION_TYPE_CONFIG[n.notification_type] ?? {
        label: n.notification_type,
        icon: <Bell className="h-3.5 w-3.5" />,
        color: "bg-muted text-muted-foreground border-border",
    };

    const handleClick = () => {
        if (!n.is_read) onMarkRead(n.id);
    };

    return (
        <div
            className={`group flex items-start gap-3 px-4 py-3 hover:bg-muted/50 transition-colors border-b last:border-b-0 ${
                !n.is_read ? "bg-primary/5" : ""
            }`}
        >
            {/* Unread dot */}
            <div className="flex-shrink-0 pt-1">
                {!n.is_read && <div className="h-2 w-2 rounded-full bg-primary" />}
            </div>

            {/* Icon */}
            <div className={`flex-shrink-0 mt-0.5 h-8 w-8 rounded-full border flex items-center justify-center ${config.color}`}>
                {config.icon}
            </div>

            {/* Content */}
            <div className="flex-1 min-w-0">
                <div className="flex items-start justify-between gap-2">
                    <button
                        type="button"
                        onClick={handleClick}
                        className="text-left flex-1 min-w-0"
                    >
                        <p className={`text-sm truncate ${!n.is_read ? "font-semibold" : "font-medium"}`}>
                            {n.title}
                        </p>
                        {n.content && (
                            <p className="text-xs text-muted-foreground mt-0.5 line-clamp-2">
                                {n.content}
                            </p>
                        )}
                        <div className="flex items-center gap-2 mt-1.5">
                            <Badge variant="outline" className={`text-xs ${config.color} border`}>
                                {config.label}
                            </Badge>
                            <span className="text-xs text-muted-foreground">
                                {formatTime(n.created_at)}
                            </span>
                        </div>
                    </button>
                </div>
            </div>

            {/* Actions */}
            <div className="flex-shrink-0 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
                {!n.is_read && (
                    <Button
                        size="sm"
                        variant="ghost"
                        className="h-7 w-7 p-0"
                        onClick={(e) => { e.stopPropagation(); onMarkRead(n.id); }}
                        title="Mark as read"
                    >
                        <Check className="h-3.5 w-3.5" />
                    </Button>
                )}
                <Button
                    size="sm"
                    variant="ghost"
                    className="h-7 w-7 p-0 text-muted-foreground hover:text-foreground"
                    onClick={(e) => { e.stopPropagation(); onArchive(n.id); }}
                    title="Archive"
                >
                    <Archive className="h-3.5 w-3.5" />
                </Button>
            </div>
        </div>
    );
}

export default function NotifyPage() {
    const queryClient = useQueryClient();
    const [filter, setFilter] = useState<Filter>("all");

    const { data, isLoading } = useQuery({
        queryKey: ["notifications", filter],
        queryFn: async () => {
            const resp = await notificationList({
                query: {
                    only_unread: filter === "unread",
                    archived: filter === "archived" ? true : undefined,
                    limit: 100,
                },
            });
            return resp.data?.data ?? null;
        },
    });

    const markReadMutation = useMutation({
        mutationFn: async (notificationId: string) => {
            await notificationMarkRead({ path: { notification_id: notificationId } });
        },
        onSuccess: () => {
            queryClient.invalidateQueries({ queryKey: ["notifications"] });
            queryClient.invalidateQueries({ queryKey: ["me"] });
        },
        onError: (err: unknown) => {
            toast.error(getApiErrorMessage(err, "Failed to mark as read"));
        },
    });

    const markAllReadMutation = useMutation({
        mutationFn: async () => {
            await notificationMarkAllRead();
        },
        onSuccess: () => {
            toast.success("All notifications marked as read");
            queryClient.invalidateQueries({ queryKey: ["notifications"] });
            queryClient.invalidateQueries({ queryKey: ["me"] });
        },
        onError: (err: unknown) => {
            toast.error(getApiErrorMessage(err, "Failed to mark all as read"));
        },
    });

    const archiveMutation = useMutation({
        mutationFn: async (notificationId: string) => {
            await notificationArchive({ path: { notification_id: notificationId } });
        },
        onSuccess: () => {
            toast.success("Notification archived");
            queryClient.invalidateQueries({ queryKey: ["notifications"] });
        },
        onError: (err: unknown) => {
            toast.error(getApiErrorMessage(err, "Failed to archive"));
        },
    });

    const notifications: NotificationResponse[] = data?.notifications ?? [];
    const total: number = data?.total ?? 0;
    const unreadCount: number = data?.unread_count ?? 0;

    return (
        <div className="max-w-3xl mx-auto p-6 space-y-4">
            {/* Header */}
            <div className="flex items-center justify-between">
                <div>
                    <h1 className="text-xl font-semibold flex items-center gap-2">
                        <Bell className="h-5 w-5" />
                        Notifications
                    </h1>
                    <p className="text-sm text-muted-foreground mt-0.5">
                        {unreadCount > 0
                            ? `${unreadCount} unread · ${total} total`
                            : `${total} notification${total !== 1 ? "s" : ""}`}
                    </p>
                </div>
                {unreadCount > 0 && filter !== "archived" && (
                    <Button
                        size="sm"
                        variant="outline"
                        onClick={() => markAllReadMutation.mutate()}
                        disabled={markAllReadMutation.isPending}
                    >
                        {markAllReadMutation.isPending ? (
                            <Loader2 className="h-3.5 w-3.5 mr-1.5 animate-spin" />
                        ) : (
                            <CheckCheck className="h-3.5 w-3.5 mr-1.5" />
                        )}
                        Mark all read
                    </Button>
                )}
            </div>

            {/* Filter tabs */}
            <div className="flex items-center gap-1 border-b">
                {(["all", "unread", "archived"] as Filter[]).map((f) => (
                    <button
                        key={f}
                        type="button"
                        onClick={() => setFilter(f)}
                        className={`px-3 py-2 text-sm font-medium border-b-2 -mb-px transition-colors ${
                            filter === f
                                ? "border-primary text-primary"
                                : "border-transparent text-muted-foreground hover:text-foreground"
                        }`}
                    >
                        {f === "all" ? "All" : f === "unread" ? "Unread" : "Archived"}
                        {f === "unread" && unreadCount > 0 && (
                            <span className="ml-1.5 inline-flex h-4 min-w-4 items-center justify-center rounded-full bg-red-500 text-[10px] font-bold text-white px-1">
                                {unreadCount}
                            </span>
                        )}
                    </button>
                ))}
            </div>

            {/* List */}
            <div className="border rounded-lg bg-card overflow-hidden">
                {isLoading ? (
                    <div className="flex items-center justify-center h-48">
                        <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
                    </div>
                ) : notifications.length === 0 ? (
                    <div className="flex flex-col items-center justify-center h-48 text-muted-foreground">
                        <BellOff className="h-10 w-10 mb-3 opacity-40" />
                        <p className="font-medium">
                            {filter === "unread" ? "No unread notifications" : filter === "archived" ? "No archived notifications" : "No notifications yet"}
                        </p>
                        <p className="text-sm mt-1">
                            {filter === "unread"
                                ? "You're all caught up!"
                                : filter === "archived"
                                ? "Archived notifications will appear here."
                                : "You'll see notifications here when something happens."}
                        </p>
                    </div>
                ) : (
                    notifications.map((n) => (
                        <NotificationItem
                            key={n.id}
                            n={n}
                            onMarkRead={(id) => markReadMutation.mutate(id)}
                            onArchive={(id) => archiveMutation.mutate(id)}
                        />
                    ))
                )}
            </div>
        </div>
    );
}
