/**
 * Horizontal drag handle between the live-preview chart and the data inspector
 * below it (spec §04). The vertical-stacking twin of the pane ResizeHandle:
 * dragging resizes the inspector's height while the chart above absorbs the
 * change, each kept above its minimum by the pure `clampInspectorHeight`.
 *
 * The span is read from the live DOM — the chart (previous sibling) and inspector
 * (next sibling) — so the divider tracks the pointer 1:1 at any pane height, the
 * same technique as PaneSplitHandle.
 *
 * Accessibility follows WAI-ARIA APG → Window Splitter (docs/architecture/10 §5),
 * the same contract as the pane handles with the axis flipped: a focusable
 * `separator` with `aria-orientation="horizontal"` reporting the inspector's 0–100
 * position via `aria-valuenow`, driven by ↑/↓ to nudge and Home/End to jump to
 * min/max. Rendered only while the inspector is open (there's nothing to resize
 * when it's collapsed).
 */

import { useLayoutEffect, useRef, useState } from 'react';
import { useResizeDrag } from '../hooks/useResizeDrag';
import { clampInspectorHeight, inspectorHeightValue, useAppStore } from '../stores/AppStore';
import styles from './InspectorSplitHandle.module.css';

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

interface InspectorSplitHandleProps {
  /** Accessible label, e.g. "Resize data inspector". */
  label: string;
  /** id of the inspector region this divider sizes (APG aria-controls). */
  controls: string;
}

export function InspectorSplitHandle({ label, controls }: InspectorSplitHandleProps) {
  const ref = useRef<HTMLDivElement>(null);
  const height = useAppStore((s) => s.dataInspectorHeight);

  /** The two regions this handle sits between: chart above, inspector below. */
  const flanks = () => ({
    chart: ref.current?.previousElementSibling as HTMLElement | null,
    inspector: ref.current?.nextElementSibling as HTMLElement | null,
  });

  // Observe the flanking regions so aria-valuenow stays correct across window and
  // pane resizes, not only divider drags.
  const [availForBoth, setAvailForBoth] = useState(0);
  useLayoutEffect(() => {
    const { chart, inspector } = flanks();
    if (!chart || !inspector) return;
    const measure = () => setAvailForBoth(chart.clientHeight + inspector.clientHeight);
    measure();
    if (typeof ResizeObserver === 'undefined') return;
    const ro = new ResizeObserver(measure);
    ro.observe(chart);
    ro.observe(inspector);
    return () => ro.disconnect();
  }, []);

  /** Apply a desired inspector height, clamped against the live span. */
  const applyHeight = (desired: number) => {
    const { chart, inspector } = flanks();
    if (!chart || !inspector) return;
    const span = chart.clientHeight + inspector.clientHeight;
    useAppStore.getState().setDataInspectorHeight(clampInspectorHeight(desired, span));
  };

  // Drag up (negative delta) grows the inspector into the chart's space.
  const onPointerDown = useResizeDrag(
    'y',
    () => flanks().inspector?.clientHeight ?? height,
    (startHeight, delta) => applyHeight(startHeight - delta),
  );

  // Keyboard per WAI-ARIA APG → Window Splitter: ↑ grows the inspector, ↓ shrinks;
  // Home/End jump to its smallest/largest allowed height.
  const onKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
    const current = flanks().inspector?.clientHeight ?? height;
    switch (e.key) {
      case 'ArrowUp':
        applyHeight(current + KEY_STEP);
        break;
      case 'ArrowDown':
        applyHeight(current - KEY_STEP);
        break;
      case 'Home': // inspector at its minimum
        applyHeight(0);
        break;
      case 'End': // inspector at its maximum (chart at its minimum)
        applyHeight(Number.MAX_SAFE_INTEGER);
        break;
      default:
        return; // not ours — let it bubble
    }
    e.preventDefault();
  };

  const valueNow = inspectorHeightValue(height, availForBoth);

  return (
    <div
      ref={ref}
      className={styles.handle}
      role="separator"
      aria-orientation="horizontal"
      aria-label={label}
      aria-controls={controls}
      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>
  );
}
