/**
 * Vertical drag handle between the library and preview when the editor is hidden
 * (spec §01A). With no editor between them to absorb the change, the two side
 * panes share the span: dragging re-splits it — one grows, the other shrinks
 * (zero-sum) — each kept above its minimum by the pure `splitLibraryWidth`.
 *
 * The split is read from the live DOM: the two flanking panes (this handle's
 * previous/next siblings) render proportionally (`flex: width 1 0`), so writing
 * their measured widths back makes the boundary track the pointer 1:1, at any
 * window size. Re-showing the editor later keeps whatever ratio was left here
 * (PanesStore → `shownSideWidths`).
 *
 * Accessibility mirrors the editor-flanking ResizeHandle (WAI-ARIA APG → Window
 * Splitter): a focusable `separator` reporting the library's 0–100 position via
 * `aria-valuenow`, driven by ←/→ to nudge and Home/End to jump to min/max. It
 * reuses ResizeHandle's stylesheet so the two handles look identical.
 */

import { useRef } from 'react';
import { splitLibraryWidth, splitValue, usePanesStore } from '../stores/PanesStore';
import styles from './ResizeHandle.module.css';

/** Keyboard nudge step (px) per arrow press — matches ResizeHandle. */
const KEY_STEP = 16;

interface PaneSplitHandleProps {
  /** Accessible label, e.g. "Resize library and preview". */
  label: string;
}

export function PaneSplitHandle({ label }: PaneSplitHandleProps) {
  const ref = useRef<HTMLDivElement>(null);

  // The reported position recomputes from the stored split as it changes. It reads
  // the *stored* ratio (container-independent, per the file header), so unlike
  // ResizeHandle aria-valuenow can drift from the rendered position after a window
  // enlargement (worst near the extremes) — an accepted simplicity trade-off, the
  // contract in arch/10 (splitter). Drag/keyboard read live clientWidth below, so
  // resizing itself stays accurate; only the announced value drifts.
  const libraryWidth = usePanesStore((s) => s.libraryWidth);
  const previewWidth = usePanesStore((s) => s.previewWidth);
  const valueNow = splitValue(libraryWidth, previewWidth);

  /** The panes this handle sits between: library before it, preview after it. */
  const flanks = () => ({
    lib: ref.current?.previousElementSibling as HTMLElement | null,
    prev: ref.current?.nextElementSibling as HTMLElement | null,
  });

  /** Apply a desired (rendered) library width, clamped against the live span. */
  const applySplit = (desiredLibrary: number) => {
    const { lib, prev } = flanks();
    if (!lib || !prev) return;
    const avail = lib.clientWidth + prev.clientWidth;
    const library = splitLibraryWidth(desiredLibrary, avail);
    usePanesStore.getState().setSplit(library, avail - library);
  };

  const onPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
    if (e.button !== 0) return; // primary button only
    e.preventDefault();
    const startX = e.clientX;
    const startLib = flanks().lib?.clientWidth ?? 0;

    const onMove = (ev: PointerEvent) => applySplit(startLib + (ev.clientX - startX));
    const onUp = () => {
      window.removeEventListener('pointermove', onMove);
      window.removeEventListener('pointerup', onUp);
      document.body.style.cursor = '';
      document.body.style.userSelect = '';
    };

    window.addEventListener('pointermove', onMove);
    window.addEventListener('pointerup', onUp);
    document.body.style.cursor = 'col-resize';
    document.body.style.userSelect = 'none';
  };

  // Keyboard per WAI-ARIA APG → Window Splitter: arrows nudge the library side;
  // Home/End jump to the library's smallest/largest allowed share of the span.
  const onKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
    const lib = flanks().lib?.clientWidth ?? 0;
    switch (e.key) {
      case 'ArrowLeft':
        applySplit(lib - KEY_STEP);
        break;
      case 'ArrowRight':
        applySplit(lib + KEY_STEP);
        break;
      case 'Home': // library at its minimum
        applySplit(0);
        break;
      case 'End': // library at its maximum (preview at its minimum)
        applySplit(Number.MAX_SAFE_INTEGER);
        break;
      default:
        return; // not ours — let it bubble
    }
    e.preventDefault();
  };

  return (
    <div
      ref={ref}
      className={styles.handle}
      role="separator"
      aria-orientation="vertical"
      aria-label={label}
      // The split governs both panes it sits between.
      aria-controls="pane-library pane-preview"
      aria-valuenow={valueNow ?? undefined}
      aria-valuemin={valueNow === null ? undefined : 0}
      aria-valuemax={valueNow === null ? undefined : 100}
      aria-valuetext={valueNow === null ? undefined : `${valueNow}%`}
      tabIndex={0}
      onPointerDown={onPointerDown}
      onKeyDown={onKeyDown}
    >
      <span className={styles.grip} aria-hidden="true" />
    </div>
  );
}
