import { h } from 'preact';
import type { VNode } from 'preact';
import type { PlotLayout } from './lib/types';

interface Props {
  layout: PlotLayout;
  /** Render the contents of a leaf pane for the given widget id. */
  renderLeaf: (widgetId: string) => VNode;
  /** When provided, dividers become draggable and report the new ratio for the
   *  split node addressed by `path` (a list of 0/1 = a/b choices from the root). */
  onResize?: (path: number[], ratio: number) => void;
}

const MIN_RATIO = 0.1;
const MAX_RATIO = 0.9;

export default function SplitLayout({ layout, renderLeaf, onResize }: Props) {
  function startDrag(e: MouseEvent, container: HTMLElement | null, dir: 'h' | 'v', path: number[]) {
    if (!onResize || !container) return;
    e.preventDefault();
    e.stopPropagation();

    function onMove(mv: MouseEvent) {
      const rect = container!.getBoundingClientRect();
      const r = dir === 'h'
        ? (mv.clientX - rect.left) / rect.width
        : (mv.clientY - rect.top) / rect.height;
      onResize!(path, Math.min(MAX_RATIO, Math.max(MIN_RATIO, r)));
    }
    function onUp() {
      document.removeEventListener('mousemove', onMove);
      document.removeEventListener('mouseup', onUp);
    }
    document.addEventListener('mousemove', onMove);
    document.addEventListener('mouseup', onUp);
  }

  function renderNode(node: PlotLayout, path: number[]): VNode {
    if (node.type === 'leaf') {
      return <div class="split-leaf">{renderLeaf(node.widget)}</div>;
    }
    const isRow = node.dir === 'h';
    let containerEl: HTMLElement | null = null;
    return (
      <div
        class={isRow ? 'split-row' : 'split-col'}
        ref={(el) => { containerEl = el as HTMLElement | null; }}
      >
        <div class="split-child" style={`flex:${node.ratio}`}>
          {renderNode(node.a, [...path, 0])}
        </div>
        <div
          class={`split-divider ${isRow ? 'split-divider-h' : 'split-divider-v'}${onResize ? '' : ' split-divider-static'}`}
          onMouseDown={(e: MouseEvent) => startDrag(e, containerEl, node.dir, path)}
        />
        <div class="split-child" style={`flex:${1 - node.ratio}`}>
          {renderNode(node.b, [...path, 1])}
        </div>
      </div>
    );
  }

  return <div class="split-root">{renderNode(layout, [])}</div>;
}
