import { useCallback, useEffect, useRef, useState } from "react";
import { useNavigate } from "react-router-dom";
import { useData, useRepos } from "../../data/DataContext";
import { useJobLive } from "../../data/JobLiveContext";
import type { AppNotification } from "../../domain/types";
import { useI18n } from "../../i18n/I18nContext";
import { pathForNotification } from "../../lib/nav";
import { formatLocalDateTime, formatTimeAgo } from "../../lib/time";
import { AppIcon, Button } from "../ui";

const PREVIEW = 5;

function kindLabel(kind: AppNotification["kind"], t: (k: string) => string): string {
  if (kind === "job") return t("nav.jobs");
  if (kind === "outbox") return t("nav.outbox");
  return t("nav.settings");
}

export function BellMenu() {
  const repos = useRepos();
  const { tick } = useData();
  const { revision } = useJobLive();
  const { t } = useI18n();
  const navigate = useNavigate();
  const [open, setOpen] = useState(false);
  const [items, setItems] = useState<AppNotification[]>([]);
  const [unread, setUnread] = useState(0);
  const rootRef = useRef<HTMLDivElement>(null);
  const loadSeq = useRef(0);

  const loadNotifs = useCallback(async () => {
    const seq = ++loadSeq.current;
    try {
      const list = await repos.notifications.list();
      if (seq !== loadSeq.current) return;
      // 未讀優先，再依時間
      const sorted = list.slice().sort((a, b) => {
        const ar = a.read_at ? 1 : 0;
        const br = b.read_at ? 1 : 0;
        if (ar !== br) return ar - br;
        return b.created_at - a.created_at;
      });
      setItems(sorted);
      setUnread(sorted.reduce((count, item) => count + (item.read_at ? 0 : 1), 0));
    } catch {
      /* ignore */
    }
  }, [repos.notifications]);

  // 全域資料變更、任務數改變或打開面板時才立即刷新。
  useEffect(() => {
    void loadNotifs();
  }, [revision, loadNotifs, tick, open]);

  // 關閉時低頻更新；頁面不可見時暫停，避免背景流量。
  useEffect(() => {
    const ms = open ? 10000 : 45000;
    const id = window.setInterval(() => {
      if (!document.hidden) void loadNotifs();
    }, ms);
    return () => window.clearInterval(id);
  }, [open, loadNotifs]);

  useEffect(() => {
    const onStore = () => void loadNotifs();
    window.addEventListener("harbor:store", onStore);
    return () => window.removeEventListener("harbor:store", onStore);
  }, [loadNotifs]);

  useEffect(() => {
    function onDoc(e: MouseEvent) {
      if (!rootRef.current?.contains(e.target as Node)) setOpen(false);
    }
    document.addEventListener("mousedown", onDoc);
    return () => document.removeEventListener("mousedown", onDoc);
  }, []);

  function openItem(n: AppNotification) {
    const wasUnread = !n.read_at;
    if (wasUnread) {
      const readAt = Date.now() * 1_000_000;
      setItems((current) => current.map((item) => (item.id === n.id ? { ...item, read_at: readAt } : item)));
      setUnread((current) => Math.max(0, current - 1));
    }
    setOpen(false);
    navigate(pathForNotification(n));
    void repos.notifications.markRead(n.id).then(
      () => window.dispatchEvent(new Event("harbor:store")),
      () => void loadNotifs(),
    );
  }

  function markAllRead() {
    const readAt = Date.now() * 1_000_000;
    setItems((current) => current.map((item) => (item.read_at ? item : { ...item, read_at: readAt })));
    setUnread(0);
    void repos.notifications.markAllRead().then(
      () => window.dispatchEvent(new Event("harbor:store")),
      () => void loadNotifs(),
    );
  }

  const preview = items.slice(0, PREVIEW);
  const more = Math.max(0, items.length - PREVIEW);

  return (
    <div className="hb-bell" ref={rootRef}>
      <button
        type="button"
        className={`hb-bell__trigger${open ? " is-open" : ""}${unread > 0 ? " has-unread" : ""}`}
        onClick={() => setOpen((v) => !v)}
        aria-expanded={open}
        aria-haspopup="menu"
        aria-label={
          unread > 0 ? `${t("topbar.notifications")}, ${t("topbar.unread", { n: unread })}` : t("topbar.notifications")
        }
        title={t("topbar.notifications")}
      >
        <span className="hb-bell__icon" aria-hidden>
          <AppIcon name="bell" size={18} />
        </span>
        {unread > 0 ? (
          <span className="hb-bell__badge">{unread > 9 ? "9+" : unread}</span>
        ) : null}
      </button>

      {open ? (
        <div className="hb-bell__panel" role="menu">
          <div className="hb-bell__head">
            <div className="hb-bell__head-title">
              <strong>{t("topbar.notifications")}</strong>
              {unread > 0 ? (
                <span className="hb-bell__head-count">
                  {t("topbar.unread", { n: unread })}
                </span>
              ) : null}
            </div>
            {items.length > 0 ? (
              <button
                type="button"
                className="hb-bell__text-btn"
                    onClick={markAllRead}
              >
                {t("topbar.markAllRead")}
              </button>
            ) : null}
          </div>

          {items.length === 0 ? (
            <p className="hb-bell__empty">{t("topbar.noNotifications")}</p>
          ) : (
            <ul className="hb-bell__list">
              {preview.map((n) => (
                <li key={n.id}>
                  <button
                    type="button"
                    className={`hb-bell__item${!n.read_at ? " is-unread" : ""}`}
                    onClick={() => openItem(n)}
                  >
                    <span className="hb-bell__item-top">
                      <span className="hb-bell__kind">{kindLabel(n.kind, t)}</span>
                      <span className="hb-bell__time" title={formatLocalDateTime(n.created_at)}>
                        {formatTimeAgo(n.created_at)}
                      </span>
                    </span>
                    <strong className="hb-bell__item-title">{n.title}</strong>
                    {n.body ? <span className="hb-bell__item-body">{n.body}</span> : null}
                  </button>
                </li>
              ))}
            </ul>
          )}

          <div className="hb-bell__foot">
            {more > 0 ? (
              <span className="text-muted hb-bell__more">
                {t("topbar.moreOlder", { n: more })}
              </span>
            ) : (
              <span />
            )}
            <Button
              type="button"
              variant="ghost"
              onClick={() => {
                setOpen(false);
                navigate("/app/jobs");
              }}
            >
              {t("topbar.jobsCenter")}
            </Button>
          </div>
        </div>
      ) : null}
    </div>
  );
}
