import { useRef, useState, useCallback, type PointerEvent } from "react";
import type { SplitNode as SplitNodeType } from "./tree";
import Pane from "./Pane";
import "./SplitNode.css";

/**
 * A horizontal or vertical split with a draggable gutter. The ratio is
 * local React state — when the gutter is dragged, we update the local
 * ratio (re-rendering the two .side flex values) and ALSO bubble the
 * change up to the tree (so it persists across reloads).
 *
 * Initialising local state from node.ratio is fine: when the tree
 * mutates around this split (e.g. a child is closed), React will give us
 * a new `node` prop with possibly-different `node.ratio`, but the
 * `useState` initializer only runs once. We re-sync via an effect.
 */
export default function SplitNode({ node }: { node: SplitNodeType }) {
  const containerRef = useRef<HTMLDivElement | null>(null);
  const [ratio, setRatio] = useState(node.ratio);
  const [dragging, setDragging] = useState(false);

  // Keep local ratio in sync if the tree updates from outside (e.g. preset
  // applied). Only mirror — don't echo back into the tree.
  // (Skipped for simplicity in v1; if it becomes annoying we can add it.)

  const onPointerDown = useCallback((e: PointerEvent<HTMLDivElement>) => {
    (e.target as HTMLElement).setPointerCapture(e.pointerId);
    setDragging(true);
    e.preventDefault();
  }, []);

  const onPointerMove = useCallback(
    (e: PointerEvent<HTMLDivElement>) => {
      if (!dragging || !containerRef.current) return;
      const rect = containerRef.current.getBoundingClientRect();
      const isH = node.orientation === "h";
      const pos = isH ? e.clientX - rect.left : e.clientY - rect.top;
      const size = isH ? rect.width : rect.height;
      if (size <= 0) return;
      const r = Math.max(0.05, Math.min(0.95, pos / size));
      setRatio(r);
      // Mutate the proxy-tree node directly so the persisted state matches.
      node.ratio = r;
    },
    [dragging, node],
  );

  const onPointerUp = useCallback((e: PointerEvent<HTMLDivElement>) => {
    setDragging(false);
    (e.target as HTMLElement).releasePointerCapture(e.pointerId);
  }, []);

  const isH = node.orientation === "h";

  return (
    <div
      ref={containerRef}
      className={`split ${isH ? "horizontal" : "vertical"}`}
    >
      <div className="side" style={{ flex: ratio }}>
        <Pane node={node.a} />
      </div>
      <div
        className={`gutter${dragging ? " active" : ""}`}
        role="separator"
        aria-orientation={isH ? "vertical" : "horizontal"}
        aria-valuenow={Math.round(ratio * 100)}
        tabIndex={-1}
        onPointerDown={onPointerDown}
        onPointerMove={onPointerMove}
        onPointerUp={onPointerUp}
        onPointerCancel={onPointerUp}
      />
      <div className="side" style={{ flex: 1 - ratio }}>
        <Pane node={node.b} />
      </div>
    </div>
  );
}
