"use client";

import { useEffect, useMemo, useState } from "react";
import { useRouter } from "next/navigation";
import { Bell, BellRing } from "lucide-react";
import { createClient } from "@/lib/supabase/client";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Switch } from "@/components/ui/switch";
import { formatTimestamp } from "@/lib/format";
import { cn } from "@/lib/utils";
import { CATEGORY_DOT, CATEGORY_STYLES } from "@/lib/status-styles";
import type { NoteCategory } from "@/lib/types";

interface Notif {
  id: string;
  actor_email: string | null;
  kind: string;
  category: string | null;
  context_label: string | null;
  body: string;
  link: string | null;
  read: boolean;
  resolved: boolean;
  created_at: string;
}

// Append a cache-busting `_t` so re-clicking the same notification re-navigates.
// Insert it into the QUERY string (before any #hash) so it stays parseable.
function bustLink(link: string): string {
  const hashIdx = link.indexOf("#");
  const base = hashIdx === -1 ? link : link.slice(0, hashIdx);
  const hash = hashIdx === -1 ? "" : link.slice(hashIdx);
  const sep = base.includes("?") ? "&" : "?";
  return base + sep + "_t=" + Date.now() + hash;
}

const KIND_LABEL: Record<string, string> = {
  mention: "mentioned you",
  thread_reply: "replied in a thread",
  action_to: "assigned you",
};

function kindText(kind: string): string {
  return KIND_LABEL[kind] ?? "notified you";
}

export function NotificationsBell({
  currentUserId,
}: {
  currentUserId: string | null;
}) {
  const supabase = useMemo(() => createClient(), []);
  const router = useRouter();
  const [items, setItems] = useState<Notif[]>([]);
  const [open, setOpen] = useState(false);
  const [showResolved, setShowResolved] = useState(false);
  const [hasAnimated, setHasAnimated] = useState(false);

  const unread = items.filter((n) => !n.read).length;
  const unresolvedCount = items.filter((n) => !n.resolved).length;

  const visible = showResolved ? items : items.filter((n) => !n.resolved);

  useEffect(() => {
    if (!currentUserId) return;
    let active = true;

    void (async () => {
      const { data } = await supabase
        .from("notifications")
        .select(
          "id,actor_email,kind,category,context_label,body,link,read,resolved,created_at",
        )
        .order("created_at", { ascending: false });
      if (active && data) setItems(data as Notif[]);
    })();

    const channel = supabase
      .channel(`notifications:${currentUserId}`)
      .on(
        "postgres_changes",
        {
          event: "INSERT",
          schema: "public",
          table: "notifications",
          filter: `recipient_id=eq.${currentUserId}`,
        },
        (payload) => setItems((prev) => [payload.new as Notif, ...prev]),
      )
      .on(
        "postgres_changes",
        {
          event: "UPDATE",
          schema: "public",
          table: "notifications",
          filter: `recipient_id=eq.${currentUserId}`,
        },
        (payload) =>
          setItems((prev) =>
            prev.map((n) =>
              n.id === (payload.new as Notif).id ? (payload.new as Notif) : n,
            ),
          ),
      )
      .subscribe();

    return () => {
      active = false;
      supabase.removeChannel(channel);
    };
  }, [supabase, currentUserId]);

  // Trigger bounce animation once on load when there are unresolved notifications
  useEffect(() => {
    if (unresolvedCount > 0 && !hasAnimated) {
      setHasAnimated(true);
    }
  }, [unresolvedCount, hasAnimated]);

  async function markRead(ids: string[]) {
    if (!ids.length) return;
    setItems((prev) =>
      prev.map((n) => (ids.includes(n.id) ? { ...n, read: true } : n)),
    );
    await supabase.from("notifications").update({ read: true }).in("id", ids);
  }

  function openNotif(n: Notif) {
    setOpen(false);
    if (!n.read) void markRead([n.id]);
    if (n.link) router.push(bustLink(n.link));
  }

  if (!currentUserId) return null;

  const BellIcon = unresolvedCount > 0 ? BellRing : Bell;
  const showBadge = unread > 0 || unresolvedCount > 0;
  const badgeCount = unread > 0 ? unread : unresolvedCount;
  const badgeIsGrey = unread === 0 && unresolvedCount > 0;

  return (
    <DropdownMenu open={open} onOpenChange={setOpen}>
      <DropdownMenuTrigger
        render={
          <button
            type="button"
            aria-label={
              unread > 0 ? `Notifications (${unread} unread)` : "Notifications"
            }
            className={cn(
              "relative inline-flex size-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
              hasAnimated &&
                unresolvedCount > 0 &&
                "animate-[bell-bounce_0.5s_ease-in-out]",
            )}
          />
        }
      >
        <BellIcon className="size-[18px]" />
        {showBadge && (
          <span
            className={cn(
              "absolute -right-0.5 -top-0.5 inline-flex min-w-4 items-center justify-center rounded-full px-1 text-[10px] font-semibold leading-4",
              badgeIsGrey
                ? "bg-muted-foreground/40 text-background"
                : "bg-primary text-primary-foreground",
            )}
          >
            {badgeCount > 9 ? "9+" : badgeCount}
          </span>
        )}
      </DropdownMenuTrigger>
      <DropdownMenuContent align="end" className="w-96 p-0">
        <div className="flex items-center justify-between border-b px-3 py-2">
          <span className="text-sm font-semibold">Notifications</span>
          <div className="flex items-center gap-3">
            <label className="flex cursor-pointer items-center gap-1.5 text-[11px] text-muted-foreground">
              <Switch
                checked={showResolved}
                onCheckedChange={setShowResolved}
              />
              Show resolved
            </label>
            {unread > 0 && (
              <button
                type="button"
                className="text-xs text-muted-foreground transition-colors hover:text-foreground"
                onClick={() =>
                  markRead(items.filter((n) => !n.read).map((n) => n.id))
                }
              >
                Mark all read
              </button>
            )}
          </div>
        </div>
        <div className="max-h-[70vh] overflow-y-auto">
          {visible.length === 0 ? (
            <p className="px-3 py-6 text-center text-sm text-muted-foreground">
              {items.length === 0
                ? "No notifications yet."
                : "No unresolved notifications."}
            </p>
          ) : (
            visible.map((n) => (
              <button
                key={n.id}
                type="button"
                onClick={() => openNotif(n)}
                className={cn(
                  "flex w-full items-start gap-2 border-b px-3 py-2 text-left transition-colors last:border-0 hover:bg-accent",
                  !n.read && "bg-primary/5",
                )}
              >
                <span
                  className={cn(
                    "mt-1.5 size-2 shrink-0 rounded-full",
                    n.read ? "bg-transparent" : "bg-primary",
                  )}
                />
                <span className="min-w-0 flex-1">
                  <span
                    className={cn(
                      "block text-sm leading-snug",
                      !n.read && "font-medium",
                    )}
                  >
                    <span className={cn(!n.read && "font-semibold")}>
                      {n.actor_email ?? "Someone"}
                    </span>{" "}
                    <span className="text-muted-foreground">
                      {kindText(n.kind)}
                    </span>
                  </span>
                  {n.context_label && (
                    <span className="mt-0.5 block text-xs text-muted-foreground">
                      on{" "}
                      <span className="font-semibold text-foreground">
                        {n.context_label}
                      </span>
                    </span>
                  )}
                  <span className="mt-1 flex flex-wrap items-center gap-1.5">
                    {n.category && (
                      <span
                        className={cn(
                          "inline-flex items-center gap-1 rounded-full border px-1.5 py-0 text-[10px] font-medium leading-4",
                          CATEGORY_STYLES[n.category as NoteCategory] ??
                            "bg-muted text-muted-foreground border-border",
                        )}
                      >
                        <span
                          className={cn(
                            "size-1.5 rounded-full",
                            CATEGORY_DOT[n.category as NoteCategory] ??
                              "bg-muted-foreground/50",
                          )}
                        />
                        {n.category}
                      </span>
                    )}
                    {n.resolved && (
                      <span className="inline-flex items-center rounded-full border border-green-200 bg-green-100 px-1.5 py-0 text-[10px] font-medium leading-4 text-green-800 dark:border-green-900 dark:bg-green-950 dark:text-green-200">
                        Resolved
                      </span>
                    )}
                  </span>
                  {n.body && (
                    <span
                      className={cn(
                        "mt-0.5 block truncate text-xs",
                        n.read
                          ? "text-muted-foreground"
                          : "text-foreground/70",
                      )}
                    >
                      {n.body}
                    </span>
                  )}
                  <span className="mt-0.5 block text-[11px] text-muted-foreground">
                    {formatTimestamp(n.created_at)}
                  </span>
                </span>
              </button>
            ))
          )}
        </div>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}
