import { splitProps, mergeProps, createSignal, onCleanup, Show, JSX } from 'solid-js';
import clsx from 'clsx';

export interface SliderProps {
  value?: number;
  defaultValue?: number;
  min?: number;
  max?: number;
  step?: number;
  onChange?: (value: number) => void;
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
  label?: string;
  showTooltip?: boolean;
  class?: string;
}

/**
 * Slider -- WAI-ARIA slider with glowing track, styled thumb, and value tooltip.
 *
 * Custom slider (not native input[type=range]) for angular clip-path geometry.
 * Supports controlled (value prop) and uncontrolled (defaultValue) modes.
 * Full keyboard support: Arrow keys, Home/End, PageUp/PageDown.
 */
export function Slider(rawProps: SliderProps) {
  const merged = mergeProps(
    {
      min: 0,
      max: 100,
      step: 1,
      size: 'md' as const,
      showTooltip: true,
    },
    rawProps,
  );
  const [local, rest] = splitProps(merged, [
    'value', 'defaultValue', 'min', 'max', 'step',
    'onChange', 'size', 'disabled', 'label', 'showTooltip', 'class',
  ]);

  // Internal state for uncontrolled mode
  const [internalValue, setInternalValue] = createSignal(local.defaultValue ?? local.min);
  const [dragging, setDragging] = createSignal(false);
  const [hovering, setHovering] = createSignal(false);

  let trackRef: HTMLDivElement | undefined;

  // Resolve value: controlled vs uncontrolled
  const currentValue = () => {
    if (local.value !== undefined) {
      return local.value;
    }
    return internalValue();
  };

  const range = () => local.max - local.min;
  const percentage = () => ((currentValue() - local.min) / range()) * 100;

  const clampAndStep = (raw: number): number => {
    // Snap to step
    const stepped = Math.round((raw - local.min) / local.step) * local.step + local.min;
    // Clamp to range
    return Math.min(local.max, Math.max(local.min, stepped));
  };

  const updateValue = (newValue: number) => {
    const clamped = clampAndStep(newValue);
    if (local.value === undefined) {
      setInternalValue(clamped);
    }
    local.onChange?.(clamped);
  };

  const getValueFromPosition = (clientX: number): number => {
    if (!trackRef) return currentValue();
    const rect = trackRef.getBoundingClientRect();
    const fraction = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
    return local.min + fraction * range();
  };

  // Mouse interaction handlers
  const handleMouseDown = (e: MouseEvent) => {
    if (local.disabled) return;
    e.preventDefault();
    setDragging(true);
    updateValue(getValueFromPosition(e.clientX));

    const handleMouseMove = (e: MouseEvent) => {
      updateValue(getValueFromPosition(e.clientX));
    };

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

    document.addEventListener('mousemove', handleMouseMove);
    document.addEventListener('mouseup', handleMouseUp);
  };

  // Keyboard interaction per WAI-ARIA slider pattern
  const handleKeyDown = (e: KeyboardEvent) => {
    if (local.disabled) return;

    let handled = true;
    const bigStep = local.step * 10;

    switch (e.key) {
      case 'ArrowRight':
      case 'ArrowUp':
        updateValue(currentValue() + local.step);
        break;
      case 'ArrowLeft':
      case 'ArrowDown':
        updateValue(currentValue() - local.step);
        break;
      case 'PageUp':
        updateValue(currentValue() + bigStep);
        break;
      case 'PageDown':
        updateValue(currentValue() - bigStep);
        break;
      case 'Home':
        updateValue(local.min);
        break;
      case 'End':
        updateValue(local.max);
        break;
      default:
        handled = false;
    }

    if (handled) {
      e.preventDefault();
    }
  };

  const showTooltipNow = () => local.showTooltip && (hovering() || dragging());

  return (
    <div
      role="slider"
      tabindex={local.disabled ? undefined : 0}
      aria-valuemin={local.min}
      aria-valuemax={local.max}
      aria-valuenow={currentValue()}
      aria-label={local.label}
      aria-disabled={local.disabled ? 'true' : undefined}
      class={clsx(
        'hh-slider',
        `hh-size-${local.size}`,
        'hh-disabled',
        dragging() && 'hh-slider--dragging',
        local.class,
      )}
      onMouseDown={handleMouseDown}
      onMouseEnter={() => setHovering(true)}
      onMouseLeave={() => setHovering(false)}
      onKeyDown={handleKeyDown}
      {...(rest as JSX.HTMLAttributes<HTMLDivElement>)}
    >
      <div class="hh-slider__track-wrapper">
        <div class="hh-slider__track" ref={trackRef}>
          <div
            class="hh-slider__fill"
            style={{ width: `${percentage()}%` }}
          />
        </div>
        <div
          class="hh-slider__thumb"
          style={{ left: `${percentage()}%` }}
        />
        <Show when={showTooltipNow()}>
          <div
            class="hh-slider__tooltip"
            style={{ left: `${percentage()}%` }}
          >
            {currentValue()}
          </div>
        </Show>
      </div>
    </div>
  );
}
