import * as React from 'react';
import { KnobContextProvider, type KnobRenderContext } from '../core/context';
import { useKnobTheme } from '../core/theme';
import type { KnobCoreProps } from '../core/types';
import { useKnob } from '../hooks/useKnob';
import { ValueInput, defaultParseValue } from './ValueInput';

export interface KnobProps extends KnobCoreProps {
  /** Square canvas size in px. Default: 80. */
  size?: number;
  /**
   * Color of the keyboard focus ring, or `false` to disable it (only do this
   * if you render your own focus indicator). Default: the theme's ring.
   */
  focusRing?: string | false;
  /**
   * Double-click opens a type-in editor instead of resetting: type an exact
   * value, Enter/blur commits, Escape cancels. Accepts "1.2k" style input.
   */
  editable?: boolean;
  /** Custom parser for typed input, e.g. to accept "-6 dB" or "A4". */
  parseValue?: (text: string) => number | null;
  className?: string;
  style?: React.CSSProperties;
  /** SVG children (Arc, Pointer, Ticks, ...) or a render function receiving the live state. */
  children?: React.ReactNode | ((ctx: KnobRenderContext) => React.ReactNode);
  /** Extra content rendered inside the wrapper but outside the SVG (e.g. HTML labels). */
  overlay?: React.ReactNode | ((ctx: KnobRenderContext) => React.ReactNode);
}

/**
 * Headless-but-visual knob container: wires up the full interaction model
 * (rotary/relative/track drag, wheel, keyboard, double-click reset, a11y)
 * and provides a render context for composable SVG primitives.
 */
export const Knob: React.FC<KnobProps> = ({
  size = 80,
  focusRing,
  editable = false,
  parseValue,
  className,
  style,
  children,
  overlay,
  ...core
}) => {
  const theme = useKnobTheme();
  const ring = focusRing ?? theme.focusRing;
  const knob = useKnob(core);
  const [editing, setEditing] = React.useState(false);

  const closeEditor = () => {
    setEditing(false);
    knob.ref.current?.focus({ preventScroll: true });
  };
  const onDoubleClick = editable
    ? (e: React.MouseEvent) => {
        e.stopPropagation();
        setEditing(true);
      }
    : knob.bind.onDoubleClick;

  const ctx: KnobRenderContext = {
    value: knob.value,
    normalized: knob.normalized,
    originNormalized: knob.originNormalized,
    angle: knob.angle,
    isDragging: knob.isDragging,
    min: knob.min,
    max: knob.max,
    decimals: knob.decimals,
    angleOffset: knob.angleOffset,
    angleRange: knob.angleRange,
    size,
    center: size / 2,
    setValue: knob.setValue,
  };

  return (
    <KnobContextProvider value={ctx}>
      <div
        {...knob.bind}
        onDoubleClick={onDoubleClick}
        className={className}
        style={{
          display: 'inline-flex',
          position: 'relative',
          width: size,
          height: size,
          borderRadius: '50%',
          ...(knob.isFocusVisible && ring ? { boxShadow: `0 0 0 2px ${ring}` } : undefined),
          ...knob.bind.style,
          ...style,
        }}
      >
        <svg
          width={size}
          height={size}
          viewBox={`0 0 ${size} ${size}`}
          style={{ display: 'block', overflow: 'visible' }}
          aria-hidden="true"
        >
          {typeof children === 'function' ? children(ctx) : children}
        </svg>
        {typeof overlay === 'function' ? overlay(ctx) : overlay}
        {editing && (
          <ValueInput
            initial={String(knob.value)}
            onCommit={raw => {
              const parsed = (parseValue ?? defaultParseValue)(raw);
              if (parsed !== null && Number.isFinite(parsed)) knob.setValue(parsed);
              closeEditor();
            }}
            onCancel={closeEditor}
          />
        )}
      </div>
    </KnobContextProvider>
  );
};
