'use client'

import * as React from 'react'
import { cn } from '../../lib/utils'

export interface SplitPaneProps {
  /** Content of the first (left / top) pane. */
  first: React.ReactNode
  /** Content of the second (right / bottom) pane. */
  second: React.ReactNode
  /** Split direction. `vertical` = side-by-side (a vertical divider). Default `vertical`. */
  orientation?: 'vertical' | 'horizontal'
  /** Initial size of the first pane, as a percentage (0-100). Default 50. */
  initialSize?: number
  /** Minimum size of the first pane as a percentage. Default 20. */
  minSize?: number
  /** Maximum size of the first pane as a percentage. Default 80. */
  maxSize?: number
  /** Keyboard nudge / step size in percentage points. Default 3. */
  step?: number
  /** Persist the size under this key in localStorage. */
  storageKey?: string
  /** Notified with the new first-pane percentage whenever it changes. */
  onResize?: (size: number) => void
  className?: string
  'aria-label'?: string
}

function clamp(v: number, min: number, max: number) {
  return Math.min(max, Math.max(min, v))
}

/**
 * Generic, app-agnostic resizable two-pane split. Drag the divider with a
 * pointer or nudge it with the arrow keys. Nothing domain-specific lives here.
 */
export function SplitPane({
  first,
  second,
  orientation = 'vertical',
  initialSize = 50,
  minSize = 20,
  maxSize = 80,
  step = 3,
  storageKey,
  onResize,
  className,
  'aria-label': ariaLabel = 'Resize panes',
}: SplitPaneProps) {
  const isVertical = orientation === 'vertical'
  const containerRef = React.useRef<HTMLDivElement>(null)
  const draggingRef = React.useRef(false)

  const [size, setSizeState] = React.useState<number>(() => {
    if (typeof window !== 'undefined' && storageKey) {
      const saved = window.localStorage.getItem(storageKey)
      if (saved != null) {
        const n = Number(saved)
        if (!Number.isNaN(n)) return clamp(n, minSize, maxSize)
      }
    }
    return clamp(initialSize, minSize, maxSize)
  })

  const setSize = React.useCallback(
    (next: number) => {
      const clamped = clamp(next, minSize, maxSize)
      setSizeState(clamped)
      onResize?.(clamped)
      if (typeof window !== 'undefined' && storageKey) {
        window.localStorage.setItem(storageKey, String(clamped))
      }
    },
    [minSize, maxSize, onResize, storageKey]
  )

  const onKeyDown = (e: React.KeyboardEvent) => {
    const grow = isVertical ? 'ArrowRight' : 'ArrowDown'
    const shrink = isVertical ? 'ArrowLeft' : 'ArrowUp'
    if (e.key === grow) {
      e.preventDefault()
      setSize(size + step)
    } else if (e.key === shrink) {
      e.preventDefault()
      setSize(size - step)
    } else if (e.key === 'Home') {
      e.preventDefault()
      setSize(minSize)
    } else if (e.key === 'End') {
      e.preventDefault()
      setSize(maxSize)
    }
  }

  const onPointerMove = React.useCallback(
    (e: PointerEvent) => {
      if (!draggingRef.current || !containerRef.current) return
      const rect = containerRef.current.getBoundingClientRect()
      const pct = isVertical
        ? ((e.clientX - rect.left) / rect.width) * 100
        : ((e.clientY - rect.top) / rect.height) * 100
      setSize(pct)
    },
    [isVertical, setSize]
  )

  const stopDragging = React.useCallback(() => {
    draggingRef.current = false
    document.body.style.cursor = ''
    document.body.style.userSelect = ''
  }, [])

  React.useEffect(() => {
    window.addEventListener('pointermove', onPointerMove)
    window.addEventListener('pointerup', stopDragging)
    return () => {
      window.removeEventListener('pointermove', onPointerMove)
      window.removeEventListener('pointerup', stopDragging)
    }
  }, [onPointerMove, stopDragging])

  const startDragging = () => {
    draggingRef.current = true
    document.body.style.cursor = isVertical ? 'col-resize' : 'row-resize'
    document.body.style.userSelect = 'none'
  }

  return (
    <div
      ref={containerRef}
      className={cn(
        'flex h-full w-full overflow-hidden',
        isVertical ? 'flex-row' : 'flex-col',
        className
      )}
      data-orientation={orientation}
    >
      <div
        className="min-h-0 min-w-0 overflow-hidden"
        style={isVertical ? { width: `${size}%` } : { height: `${size}%` }}
        data-pane="first"
      >
        {first}
      </div>
      <div
        role="separator"
        aria-label={ariaLabel}
        aria-orientation={orientation}
        aria-valuenow={Math.round(size)}
        aria-valuemin={minSize}
        aria-valuemax={maxSize}
        tabIndex={0}
        onKeyDown={onKeyDown}
        onPointerDown={startDragging}
        className={cn(
          'group relative shrink-0 bg-border transition-colors hover:bg-primary/40 focus-visible:bg-primary/60 focus:outline-none',
          isVertical ? 'w-1 cursor-col-resize' : 'h-1 cursor-row-resize'
        )}
        data-testid="split-pane-resizer"
      >
        <span
          aria-hidden="true"
          className={cn(
            'absolute bg-transparent',
            isVertical ? '-inset-x-1.5 inset-y-0' : '-inset-y-1.5 inset-x-0'
          )}
        />
      </div>
      <div className="min-h-0 min-w-0 flex-1 overflow-hidden" data-pane="second">
        {second}
      </div>
    </div>
  )
}
