// Exercise 1: fix the flickering tooltip
//
// `TooltipBad` measures the anchor/tooltip AFTER paint (useEffect), so on
// mount the tooltip briefly renders at (0, 0) before snapping to the right
// spot — a visible flash. Fix it in `TooltipGood` by switching to
// useLayoutEffect so the position is correct on the FIRST paint.
//
// TODO 1: implement computeTooltipPosition (pure, no React/DOM)
// TODO 2: switch TooltipGood to useLayoutEffect and call computeTooltipPosition

import { useEffect, useLayoutEffect, useRef, useState } from "react";

interface Rect {
  top: number;
  left: number;
  width: number;
  height: number;
}

interface Position {
  top: number;
  left: number;
}

// TODO 1: given the anchor's rect, the tooltip's own size, and the viewport
// size, return the {top, left} to render the tooltip at. Place it directly
// below the anchor; if it would overflow the bottom of the viewport, place
// it above the anchor instead. Always align left edges.
function computeTooltipPosition(
  anchorRect: Rect,
  tooltipSize: { width: number; height: number },
  viewport: { width: number; height: number }
): Position {
  return { top: 0, left: 0 };
  // TODO: const belowTop = anchorRect.top + anchorRect.height;
  // if (belowTop + tooltipSize.height > viewport.height) {
  //   return { top: anchorRect.top - tooltipSize.height, left: anchorRect.left };
  // }
  // return { top: belowTop, left: anchorRect.left };
}

// --- reference component showing the BUG (do not fix this one, read it) ---
function TooltipBad({ anchorRef }: { anchorRef: React.RefObject<HTMLElement> }) {
  const tooltipRef = useRef<HTMLDivElement>(null);
  const [pos, setPos] = useState<Position>({ top: 0, left: 0 });

  useEffect(() => {
    if (!anchorRef.current || !tooltipRef.current) return;
    const a = anchorRef.current.getBoundingClientRect();
    const t = tooltipRef.current.getBoundingClientRect();
    setPos(
      computeTooltipPosition(a, { width: t.width, height: t.height }, {
        width: window.innerWidth,
        height: window.innerHeight,
      })
    );
  }, [anchorRef]);

  return (
    <div ref={tooltipRef} style={{ position: "fixed", top: pos.top, left: pos.left }}>
      Bad tooltip (flashes at 0,0 first)
    </div>
  );
}

// TODO 2: fix by using useLayoutEffect instead of useEffect
function TooltipGood({ anchorRef }: { anchorRef: React.RefObject<HTMLElement> }) {
  const tooltipRef = useRef<HTMLDivElement>(null);
  const [pos, setPos] = useState<Position>({ top: 0, left: 0 });

  useEffect(() => {
    // TODO: change this to useLayoutEffect so the fix happens before paint
    if (!anchorRef.current || !tooltipRef.current) return;
    const a = anchorRef.current.getBoundingClientRect();
    const t = tooltipRef.current.getBoundingClientRect();
    setPos(
      computeTooltipPosition(a, { width: t.width, height: t.height }, {
        width: window.innerWidth,
        height: window.innerHeight,
      })
    );
  }, [anchorRef]);

  return (
    <div ref={tooltipRef} style={{ position: "fixed", top: pos.top, left: pos.left }}>
      Good tooltip (correct on first paint)
    </div>
  );
}

export { TooltipBad, TooltipGood, computeTooltipPosition };

// --- self-check: do not modify below this line ---
const belowFits = computeTooltipPosition(
  { top: 100, left: 50, width: 80, height: 30 },
  { width: 120, height: 40 },
  { width: 800, height: 600 }
);
const belowFitsOk = belowFits.top === 130 && belowFits.left === 50;

const overflowsBottom = computeTooltipPosition(
  { top: 580, left: 50, width: 80, height: 30 },
  { width: 120, height: 40 },
  { width: 800, height: 600 }
);
const flippedAboveOk = overflowsBottom.top === 540; // 580 - 40

console.log(belowFitsOk ? "PASS (renders below when it fits)" : "FAIL (renders below when it fits)");
console.log(flippedAboveOk ? "PASS (flips above when it would overflow)" : "FAIL (flips above when it would overflow)");

// Verify visually: mount TooltipBad and TooltipGood near a positioned anchor
// element. TooltipBad should visibly jump from (0,0) to its final position
// on mount (a flash); TooltipGood should appear directly in its final
// position with no visible jump.
