"use client";

import { useState } from "react";
import { createPortal } from "react-dom";
import { useTheme } from "next-themes";

import { MarkdownPreview } from "@/components/markdown/markdown-widgets";

const OFFSET = 16;
// Rough size assumptions used to keep the tooltip on-screen -- cheaper than
// measuring the rendered node and repositioning after the fact, and close
// enough for a small hover preview.
const ASSUMED_WIDTH = 288;
const ASSUMED_HEIGHT = 180;

/**
 * Wraps its child in a tooltip that tracks the cursor instead of anchoring
 * to the trigger element -- rendered via a portal to `document.body` so it
 * isn't caught by an ancestor's CSS `transform` (dnd-kit positions dragged
 * cards with one, which would otherwise turn `position: fixed` here into
 * "fixed to that card" instead of the viewport). Content is rendered as
 * markdown, same as the editor it was written in, so links etc. actually
 * show up as links in the preview too.
 */
export function MouseFollowTooltip({
  content,
  children,
}: {
  content: string;
  children: React.ReactNode;
}) {
  const { resolvedTheme } = useTheme();
  const colorMode = resolvedTheme === "dark" ? "dark" : "light";
  const [pos, setPos] = useState<{ x: number; y: number } | null>(null);

  function handleMove(e: React.MouseEvent) {
    setPos({ x: e.clientX, y: e.clientY });
  }

  let left = 0;
  let top = 0;
  if (pos) {
    left = pos.x + OFFSET;
    top = pos.y + OFFSET;
    if (typeof window !== "undefined") {
      if (left + ASSUMED_WIDTH > window.innerWidth) left = pos.x - ASSUMED_WIDTH - OFFSET;
      if (top + ASSUMED_HEIGHT > window.innerHeight) top = pos.y - ASSUMED_HEIGHT - OFFSET;
    }
  }

  return (
    <span
      className="contents"
      onMouseEnter={handleMove}
      onMouseMove={handleMove}
      onMouseLeave={() => setPos(null)}
    >
      {children}
      {pos &&
        typeof document !== "undefined" &&
        createPortal(
          <div
            role="tooltip"
            data-color-mode={colorMode}
            className="pointer-events-none fixed z-50 max-h-44 w-72 overflow-hidden rounded-md border bg-popover p-2.5 text-xs text-popover-foreground shadow-md"
            style={{ left, top }}
          >
            <MarkdownPreview source={content} />
          </div>,
          document.body
        )}
    </span>
  );
}
