"use client";

import { useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { Info } from "lucide-react";

// Hilfetext-Bubble.
//
// Der Text wird über ein PORTAL an den <body> gehängt und `fixed` positioniert. Vorher lag er
// als `absolute` Kind im Fluss -- in einem scrollenden Dialog (Verteil-Dialoge, Assistent)
// schnitt dessen `overflow` die Box ab, teilweise nach wenigen Zeilen. Fix positioniert
// bezieht sich auf den Viewport und entkommt damit jedem Overflow-Container.
//
// Zusätzlich: Die Box klappt nach OBEN, wenn unten kein Platz mehr ist, und wird an den
// Bildschirmrändern geklemmt, damit sie nie halb ausserhalb steht.

const WIDTH = 256; // entspricht w-64
const MARGIN = 8;

export function InfoBubble({ text }: { text: string }) {
  const [open, setOpen] = useState(false);
  const [pos, setPos] = useState<{ top: number; left: number } | null>(null);
  const btnRef = useRef<HTMLButtonElement | null>(null);
  const boxRef = useRef<HTMLDivElement | null>(null);

  // Position aus der Lage des Knopfes berechnen -- erst wenn geöffnet, und erneut, sobald die
  // tatsächliche Höhe der Box bekannt ist (für das Hochklappen).
  useEffect(() => {
    if (!open) {
      // eslint-disable-next-line react-hooks/set-state-in-effect -- Position gilt nur im offenen Zustand
      setPos(null);
      return;
    }
    const place = () => {
      const btn = btnRef.current;
      if (!btn) return;
      const r = btn.getBoundingClientRect();
      const height = boxRef.current?.offsetHeight ?? 0;
      const spaceBelow = window.innerHeight - r.bottom;
      const above = height > 0 && spaceBelow < height + MARGIN && r.top > height + MARGIN;
      const left = Math.min(
        Math.max(MARGIN, r.left + r.width / 2 - WIDTH / 2),
        Math.max(MARGIN, window.innerWidth - WIDTH - MARGIN)
      );
      setPos({ top: above ? r.top - height - 6 : r.bottom + 6, left });
    };
    place();
    // Nach dem ersten Zeichnen erneut -- dann steht die Höhe fest.
    const raf = requestAnimationFrame(place);
    window.addEventListener("scroll", place, true);
    window.addEventListener("resize", place);
    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener("scroll", place, true);
      window.removeEventListener("resize", place);
    };
  }, [open]);

  return (
    <span className="relative inline-flex align-middle ml-1">
      <button
        ref={btnRef}
        type="button"
        aria-label="Hilfe anzeigen"
        onMouseEnter={() => setOpen(true)}
        onMouseLeave={() => setOpen(false)}
        onClick={(e) => {
          e.stopPropagation();
          setOpen((o) => !o);
        }}
        className="flex h-4 w-4 items-center justify-center rounded-full bg-accent-soft text-accent-soft-fg hover:opacity-80"
      >
        <Info className="h-2.5 w-2.5" strokeWidth={2.5} />
      </button>
      {open &&
        typeof document !== "undefined" &&
        createPortal(
          <div
            ref={boxRef}
            role="tooltip"
            style={{
              position: "fixed",
              top: pos?.top ?? -9999,
              left: pos?.left ?? -9999,
              width: WIDTH,
              // Vor der ersten Messung unsichtbar, damit die Box nicht kurz aufblitzt.
              visibility: pos ? "visible" : "hidden",
            }}
            className="pointer-events-none z-[60] rounded-lg border border-border bg-surface p-2.5 text-xs leading-snug text-fg shadow-lg"
          >
            {text}
          </div>,
          document.body
        )}
    </span>
  );
}
