"use client";

import { useEffect, useRef, useState } from "react";
import Link from "next/link";
import { api } from "@/lib/api-client";
import { useSession } from "@/components/session-provider";
import { Avatar } from "@/components/ui";
import { timeAgo } from "@/lib/format";

type Notification = {
  id: string;
  type: string;
  title: string;
  body: string | null;
  linkUrl: string | null;
  thumbnailUrl: string | null;
  isRead: boolean;
  createdAt: string;
};

/** Bell + realtime notification centre backed by Server-Sent Events. */
export function NotificationBell() {
  const { user, unread, setUnread } = useSession();
  const [open, setOpen] = useState(false);
  const [items, setItems] = useState<Notification[]>([]);
  const [connected, setConnected] = useState(false);
  const ref = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    if (!open || !user) return;
    void api<{ items: Notification[]; unread: number }>("/api/notifications")
      .then((data) => {
        setItems(data.items);
        setUnread(data.unread);
      })
      .catch(() => undefined);
  }, [open, user, setUnread]);

  useEffect(() => {
    if (!user) return;
    const source = new EventSource("/api/realtime");
    source.onopen = () => setConnected(true);
    source.onerror = () => setConnected(false);
    source.onmessage = (event) => {
      try {
        const payload = JSON.parse(event.data) as {
          kind: string;
          notification?: Notification;
        };
        if (payload.kind === "notification" && payload.notification) {
          setItems((prev) => [payload.notification!, ...prev].slice(0, 60));
          setUnread((n) => n + 1);
        }
      } catch {
        /* ignore malformed frame */
      }
    };
    return () => source.close();
  }, [user, setUnread]);

  useEffect(() => {
    const onClick = (event: MouseEvent) => {
      if (ref.current && !ref.current.contains(event.target as Node)) setOpen(false);
    };
    document.addEventListener("mousedown", onClick);
    return () => document.removeEventListener("mousedown", onClick);
  }, []);

  if (!user) return null;

  const markAll = async () => {
    const data = await api<{ unread: number }>("/api/notifications", { method: "POST", json: { all: true } });
    setUnread(data.unread);
    setItems((prev) => prev.map((i) => ({ ...i, isRead: true })));
  };

  const markOne = async (id: string) => {
    const data = await api<{ unread: number }>("/api/notifications", { method: "POST", json: { ids: [id] } });
    setUnread(data.unread);
    setItems((prev) => prev.map((i) => (i.id === id ? { ...i, isRead: true } : i)));
  };

  return (
    <div className="relative" ref={ref}>
      <button
        aria-label="Notifications"
        onClick={() => setOpen((v) => !v)}
        className="relative grid h-10 w-10 place-items-center rounded-full hover:bg-surface"
      >
        <svg viewBox="0 0 24 24" className="h-6 w-6" fill="currentColor">
          <path d="M12 22a2.2 2.2 0 0 0 2.2-2.2H9.8A2.2 2.2 0 0 0 12 22zm7-5.8v-1l1.6-1.6a1 1 0 0 0 0-1.4l-.7-.7a1 1 0 0 0-1.4 0L17 12h-1a7 7 0 1 0-8 0H7l-1.5-1.5a1 1 0 0 0-1.4 0l-.7.7a1 1 0 0 0 0 1.4L5 15.2v1z" />
        </svg>
        {unread > 0 ? (
          <span className="absolute right-1 top-1 min-w-[18px] rounded-full bg-brand px-1 text-[10px] font-bold leading-[18px] text-white">
            {unread > 9 ? "9+" : unread}
          </span>
        ) : null}
      </button>

      {open ? (
        <div className="animate-fade-up absolute right-0 top-12 z-50 max-h-[70vh] w-[min(92vw,26rem)] overflow-y-auto rounded-xl border border-line bg-bg-elevated shadow-2xl">
          <div className="sticky top-0 z-10 flex items-center justify-between border-b border-line bg-bg-elevated px-4 py-3">
            <span className="font-semibold">Notifications</span>
            <span className="flex items-center gap-2 text-xs text-muted">
              <span className={`h-2 w-2 rounded-full ${connected ? "bg-green-500" : "bg-muted"}`} />
              {connected ? "live" : "offline"}
              <button onClick={markAll} className="font-semibold text-brand">
                Mark all read
              </button>
            </span>
          </div>
          {items.length === 0 ? (
            <p className="p-6 text-center text-sm text-muted">No notifications yet.</p>
          ) : (
            items.map((item) => {
              const inner = (
                <div className={`flex gap-3 px-4 py-3 transition hover:bg-surface ${item.isRead ? "" : "bg-brand/5"}`}>
                  {item.thumbnailUrl ? (
                    // eslint-disable-next-line @next/next/no-img-element
                    <img src={item.thumbnailUrl} alt="" className="h-12 w-20 shrink-0 rounded object-cover" />
                  ) : (
                    <span className="grid h-10 w-10 shrink-0 place-items-center rounded-full bg-surface text-lg" aria-hidden>
                      {item.type === "new_subscriber" ? "🙌" : item.type === "live" ? "🔴" : item.type === "monetization" ? "💰" : "💬"}
                    </span>
                  )}
                  <div className="min-w-0 flex-1">
                    <p className="line-clamp-2 text-sm font-medium">{item.title}</p>
                    {item.body ? <p className="line-clamp-1 text-xs text-muted">{item.body}</p> : null}
                    <p className="mt-0.5 text-[11px] text-muted">{timeAgo(item.createdAt)}</p>
                  </div>
                  {!item.isRead ? <span className="mt-1 h-2 w-2 shrink-0 rounded-full bg-brand" /> : null}
                </div>
              );
              return item.linkUrl ? (
                <Link key={item.id} href={item.linkUrl} onClick={() => void markOne(item.id)}>
                  {inner}
                </Link>
              ) : (
                <div key={item.id}>{inner}</div>
              );
            })
          )}
          <Link href="/notifications" className="block border-t border-line px-4 py-3 text-center text-sm font-semibold text-brand hover:bg-surface">
            See all notifications
          </Link>
        </div>
      ) : null}
    </div>
  );
}

export function NotificationsPage() {
  const { user } = useSession();
  const [items, setItems] = useState<Notification[] | null>(null);
  const [filter, setFilter] = useState<"all" | "unread">("all");

  useEffect(() => {
    if (!user) return;
    void api<{ items: Notification[] }>("/api/notifications")
      .then((data) => setItems(data.items))
      .catch(() => setItems([]));
  }, [user]);

  if (!user) return <p className="p-6 text-sm text-muted">Sign in to see your notifications.</p>;
  if (!items) return <div className="skeleton h-40 w-full rounded-xl" />;
  const filtered = filter === "unread" ? items.filter((i) => !i.isRead) : items;

  return (
    <div className="space-y-4">
      <div className="flex gap-2">
        {(["all", "unread"] as const).map((key) => (
          <button
            key={key}
            onClick={() => setFilter(key)}
            className={`rounded-full px-4 py-1.5 text-sm font-medium ${filter === key ? "bg-fg text-bg" : "bg-chip"}`}
          >
            {key === "all" ? "All" : "Unread"}
          </button>
        ))}
      </div>
      {filtered.length === 0 ? (
        <p className="rounded-xl border border-line p-8 text-center text-sm text-muted">Nothing here.</p>
      ) : (
        filtered.map((item) => (
          <Link
            key={item.id}
            href={item.linkUrl ?? "#"}
            className="flex gap-3 rounded-xl border border-line p-3 transition hover:bg-surface"
          >
            <Avatar name={item.title} src={item.thumbnailUrl} size={44} className="!rounded-lg" />
            <div className="min-w-0 flex-1">
              <p className="text-sm font-medium">{item.title}</p>
              {item.body ? <p className="text-xs text-muted">{item.body}</p> : null}
              <p className="text-[11px] text-muted">{timeAgo(item.createdAt)}</p>
            </div>
          </Link>
        ))
      )}
    </div>
  );
}
