import * as React from 'react'

import { cn } from './utils'

/* ------------------------------------------------------------------ */
/* Types                                                               */
/* ------------------------------------------------------------------ */

export type SplitOrientation = 'horizontal' | 'vertical'

export interface SplitPaneProps extends Omit<React.ComponentProps<'div'>, 'children'> {
  /** Layout orientation */
  orientation?: SplitOrientation
  /** Default size of the first pane as a percentage (0-100) */
  defaultSize?: number
  /** Minimum size of each pane in pixels */
  minSize?: number
  /** Gutter (divider) width in pixels */
  gutterSize?: number
  /** Callback fired during resize with first pane's size percentage */
  onResize?: (size: number) => void
  /** The two panes as children */
  children: [React.ReactNode, React.ReactNode]
}

/* ------------------------------------------------------------------ */
/* Component                                                           */
/* ------------------------------------------------------------------ */

function SplitPane({
  className,
  orientation = 'horizontal',
  defaultSize = 50,
  minSize = 0,
  gutterSize = 4,
  onResize,
  children,
  ...props
}: SplitPaneProps) {
  const [firstSize, setFirstSize] = React.useState(defaultSize)
  const containerRef = React.useRef<HTMLDivElement>(null)
  const isDragging = React.useRef(false)

  const handleMouseDown = React.useCallback(
    (e: React.MouseEvent) => {
      e.preventDefault()
      isDragging.current = true

      const handleMouseMove = (event: MouseEvent) => {
        if (!isDragging.current || !containerRef.current) return

        const rect = containerRef.current.getBoundingClientRect()
        let ratio: number

        if (orientation === 'horizontal') {
          const x = event.clientX - rect.left
          ratio = rect.width > 0 ? (x / rect.width) * 100 : 50
        } else {
          const y = event.clientY - rect.top
          ratio = rect.height > 0 ? (y / rect.height) * 100 : 50
        }

        // Enforce min sizes
        const totalPx = orientation === 'horizontal' ? rect.width : rect.height
        const minPercent = totalPx > 0 ? (minSize / totalPx) * 100 : 0
        const clamped = Math.max(minPercent, Math.min(100 - minPercent, ratio))

        setFirstSize(clamped)
        onResize?.(clamped)
      }

      const handleMouseUp = () => {
        isDragging.current = false
        document.removeEventListener('mousemove', handleMouseMove)
        document.removeEventListener('mouseup', handleMouseUp)
      }

      document.addEventListener('mousemove', handleMouseMove)
      document.addEventListener('mouseup', handleMouseUp)
    },
    [orientation, minSize, onResize]
  )

  const isHorizontal = orientation === 'horizontal'
  const [first, second] = children

  return (
    <div
      ref={containerRef}
      data-slot="split-pane"
      className={cn('flex h-full w-full', isHorizontal ? 'flex-row' : 'flex-col', className)}
      {...props}
    >
      {/* First pane */}
      <div
        data-slot="split-pane-panel"
        className="overflow-auto"
        style={{
          [isHorizontal ? 'width' : 'height']:
            `calc(${String(firstSize)}% - ${String(gutterSize / 2)}px)`,
          flexShrink: 0,
        }}
      >
        {first}
      </div>

      {/* Gutter */}
      <div
        data-slot="split-pane-gutter"
        className={cn(
          'shrink-0 bg-border-glass transition-colors hover:bg-primary/40',
          isHorizontal ? 'cursor-col-resize' : 'cursor-row-resize'
        )}
        style={{
          [isHorizontal ? 'width' : 'height']: `${String(gutterSize)}px`,
        }}
        onMouseDown={handleMouseDown}
        role="separator"
        aria-orientation={orientation}
        aria-valuenow={Math.round(firstSize)}
        aria-valuemin={0}
        aria-valuemax={100}
        tabIndex={0}
        onKeyDown={e => {
          const step = 2
          if ((isHorizontal && e.key === 'ArrowLeft') || (!isHorizontal && e.key === 'ArrowUp')) {
            e.preventDefault()
            const next = Math.max(0, firstSize - step)
            setFirstSize(next)
            onResize?.(next)
          }
          if (
            (isHorizontal && e.key === 'ArrowRight') ||
            (!isHorizontal && e.key === 'ArrowDown')
          ) {
            e.preventDefault()
            const next = Math.min(100, firstSize + step)
            setFirstSize(next)
            onResize?.(next)
          }
        }}
      />

      {/* Second pane */}
      <div
        data-slot="split-pane-panel"
        className="overflow-auto"
        style={{
          [isHorizontal ? 'width' : 'height']:
            `calc(${String(100 - firstSize)}% - ${String(gutterSize / 2)}px)`,
          flexShrink: 0,
        }}
      >
        {second}
      </div>
    </div>
  )
}

export { SplitPane }
