import { useEffect, useRef, useState, useSyncExternalStore } from "react";
import { createPortal } from "react-dom";
import { useTranslation } from "react-i18next";
import type { TFunction } from "i18next";
import { useQueryClient } from "@tanstack/react-query";
import { Bell, Eye, RotateCcw, Search, Trash2 } from "lucide-react";
import { api, type FeedFilters } from "../lib/api";
import {
  clearAll,
  dismiss,
  getNotifications,
  getUnreadCount,
  markAllRead,
  notify,
  subscribe,
  type VideoHiddenMeta,
  type VideoWatchedMeta,
} from "../lib/notifications";
import { LEVEL_STYLE } from "./Toaster";

function relTime(ts: number, t: TFunction): string {
  const s = Math.round((Date.now() - ts) / 1000);
  if (s < 60) return t("notifications.time.justNow");
  const m = Math.round(s / 60);
  if (m < 60) return t("notifications.time.minutes", { count: m });
  const h = Math.round(m / 60);
  if (h < 24) return t("notifications.time.hours", { count: h });
  const d = Math.round(h / 24);
  return t("notifications.time.days", { count: d });
}

export default function NotificationCenter({
  filters,
  setFilters,
  variant = "header",
}: {
  filters: FeedFilters;
  setFilters: (f: FeedFilters) => void;
  variant?: "header" | "rail";
}) {
  const { t } = useTranslation();
  const notifications = useSyncExternalStore(subscribe, getNotifications, getNotifications);
  const unread = useSyncExternalStore(subscribe, getUnreadCount, getUnreadCount);
  const [open, setOpen] = useState(false);
  const wrap = useRef<HTMLDivElement>(null);
  const btnRef = useRef<HTMLButtonElement>(null);
  const panelRef = useRef<HTMLDivElement>(null);
  // Rail variant anchors the panel right + above the button (fixed, viewport coords) and
  // portals it to <body> so it escapes the nav's backdrop-filter.
  const [pos, setPos] = useState<{ left: number; bottom: number }>({ left: 0, bottom: 0 });
  const qc = useQueryClient();

  // Close when clicking anywhere outside the button + panel.
  useEffect(() => {
    if (!open) return;
    function onDown(e: MouseEvent) {
      const target = e.target as Node;
      if (btnRef.current?.contains(target) || panelRef.current?.contains(target)) return;
      if (variant === "header" && wrap.current?.contains(target)) return;
      setOpen(false);
    }
    document.addEventListener("mousedown", onDown);
    return () => document.removeEventListener("mousedown", onDown);
  }, [open, variant]);

  function toggle() {
    if (!open && variant === "rail") {
      const r = btnRef.current?.getBoundingClientRect();
      if (r) setPos({ left: r.right + 8, bottom: window.innerHeight - r.bottom });
    }
    setOpen((o) => !o);
  }

  // Opening the center marks everything read.
  useEffect(() => {
    if (open) markAllRead();
  }, [open, notifications.length]);

  function locateHidden(meta: VideoHiddenMeta) {
    setFilters({
      ...filters,
      show: "hidden",
      channelId: meta.channelId || undefined,
      channelName: meta.channelName || undefined,
    });
    setOpen(false);
  }

  function revertState(
    meta: VideoHiddenMeta | VideoWatchedMeta,
    messageKey: "notifications.unhidden" | "notifications.unwatched"
  ) {
    api
      .setState(meta.videoId, "new")
      .then(() => {
        qc.invalidateQueries({ queryKey: ["feed"] });
        qc.invalidateQueries({ queryKey: ["feed-count"] });
        notify({ level: "success", message: t(messageKey, { title: meta.title }) });
      })
      .catch(() => {});
  }

  function renderPanel(el: JSX.Element) {
    if (variant !== "rail") return el;
    return createPortal(
      <div style={{ position: "fixed", left: pos.left, bottom: pos.bottom, zIndex: 40 }}>
        {el}
      </div>,
      document.body
    );
  }

  return (
    <div className="relative" ref={wrap}>
      <button
        ref={btnRef}
        onClick={toggle}
        title={t("notifications.title")}
        className="relative p-2 rounded-lg text-muted hover:text-fg hover:bg-card transition"
      >
        <Bell className="w-5 h-5" />
        {unread > 0 && (
          <span className="absolute -top-0.5 -right-0.5 min-w-[16px] h-4 px-1 rounded-full bg-accent text-accent-fg text-[10px] font-bold grid place-items-center">
            {unread > 9 ? "9+" : unread}
          </span>
        )}
      </button>

      {open &&
        renderPanel(
          <div
            ref={panelRef}
            className={`glass-menu w-80 max-w-[calc(100vw-2rem)] rounded-xl flex flex-col max-h-[70vh] animate-[popIn_0.16s_ease] ${
              variant === "rail" ? "" : "absolute right-0 mt-2 z-30"
            }`}
          >
          <div className="flex items-center justify-between px-3 py-2 border-b border-border">
            <div className="text-sm font-semibold">{t("notifications.title")}</div>
            {notifications.length > 0 && (
              <button
                onClick={clearAll}
                className="flex items-center gap-1 text-xs text-muted hover:text-accent transition"
                title={t("notifications.clearAll")}
              >
                <Trash2 className="w-3.5 h-3.5" />
                {t("notifications.clear")}
              </button>
            )}
          </div>

          <div className="overflow-y-auto">
            {notifications.length === 0 ? (
              <div className="px-3 py-8 text-center text-sm text-muted">{t("notifications.empty")}</div>
            ) : (
              notifications.map((n) => {
                const { icon: Icon, color } = LEVEL_STYLE[n.level];
                const needsAction = n.requiresInteraction && !n.dismissed;
                const hidden = n.meta?.kind === "video-hidden" ? n.meta : null;
                const watched = n.meta?.kind === "video-watched" ? n.meta : null;
                return (
                  <div
                    key={n.id}
                    className={`flex items-start gap-2.5 px-3 py-2.5 border-b border-border/60 ${
                      needsAction ? "bg-accent/5" : ""
                    }`}
                  >
                    <Icon className={`w-4 h-4 shrink-0 mt-0.5 ${color}`} />
                    <div className="min-w-0 flex-1">
                      {n.title && <div className="text-sm font-semibold">{n.title}</div>}
                      <div className="text-sm break-words">{n.message}</div>
                      <div className="flex items-center gap-2 mt-0.5">
                        <span className="text-[11px] text-muted">{relTime(n.ts, t)}</span>
                        {needsAction && (
                          <span className="text-[10px] uppercase tracking-wide font-semibold text-accent">
                            {t("notifications.actionNeeded")}
                          </span>
                        )}
                      </div>

                      {hidden ? (
                        <div className="flex items-center gap-3 mt-1">
                          <button
                            onClick={() => locateHidden(hidden)}
                            className="flex items-center gap-1 text-accent text-sm font-semibold hover:underline"
                          >
                            <Search className="w-3.5 h-3.5" />
                            {t("notifications.findInFeed")}
                          </button>
                          <button
                            onClick={() => revertState(hidden, "notifications.unhidden")}
                            className="flex items-center gap-1 text-accent text-sm font-semibold hover:underline"
                          >
                            <Eye className="w-3.5 h-3.5" />
                            {t("notifications.unhide")}
                          </button>
                        </div>
                      ) : watched ? (
                        <div className="flex items-center gap-3 mt-1">
                          <button
                            onClick={() => revertState(watched, "notifications.unwatched")}
                            className="flex items-center gap-1 text-accent text-sm font-semibold hover:underline"
                          >
                            <RotateCcw className="w-3.5 h-3.5" />
                            {t("notifications.unwatch")}
                          </button>
                        </div>
                      ) : (
                        n.action &&
                        !n.dismissed && (
                          <button
                            onClick={() => {
                              n.action!.onClick();
                              dismiss(n.id);
                            }}
                            className="mt-1 text-accent text-sm font-semibold hover:underline"
                          >
                            {n.action.label}
                          </button>
                        )
                      )}
                    </div>
                  </div>
                );
              })
            )}
          </div>
        </div>
      )}
    </div>
  );
}
