import clsx from "clsx";
import { useId, useState, React } from "react";
import {
  KnobHeadless,
  KnobHeadlessLabel,
  KnobHeadlessOutput,
  useKnobKeyboardControls,
} from "react-knob-headless";
import { mapFrom01Linear, mapTo01Linear } from "@dsp-ts/math";
import { KnobBaseThumb } from "./KnobBaseThumb";

export function KnobBase({
  theme,
  label,
  valueDefault,
  valueMin,
  valueMax,
  valueRawRoundFn,
  valueRawDisplayFn,
  axis,
  stepFn,
  stepLargerFn,
  mapTo01 = mapTo01Linear,
  mapFrom01 = mapFrom01Linear,
}) {
  KnobBase.propTypes = {
    theme: KnobBase.string,
    label: KnobBase.string,
    valueDefault: KnobBase.number,
    valueMin: KnobBase.number,
    valueMax: KnobBase.number,
    valueRawRoundFn: KnobBase.func,
    valueRawDisplayFn: KnobBase.func,
    axis: KnobBase.string,
    stepFn: KnobBase.func,
    stepLargerFn: KnobBase.func,
    mapTo01: KnobBase.func,
    mapFrom01: KnobBase.func,
  };
  const knobId = useId();
  const labelId = useId();
  const [valueRaw, setValueRaw] = useState(valueDefault);
  const value01 = mapTo01(valueRaw, valueMin, valueMax);
  const step = stepFn(valueRaw);
  const stepLarger = stepLargerFn(valueRaw);
  const dragSensitivity = 0.006;

  const keyboardControlHandlers = useKnobKeyboardControls({
    valueRaw,
    valueMin,
    valueMax,
    step,
    stepLarger,
    onValueRawChange: setValueRaw,
  });

  return (
    <div
      className={clsx(
        "w-16 flex flex-col gap-0.5 justify-center items-center text-xs select-none",
        "outline-none focus-within:outline-1 focus-within:outline-offset-4 focus-within:outline-stone-300"
      )}
    >
      <KnobHeadlessLabel id={labelId}>{label}</KnobHeadlessLabel>
      <KnobHeadless
        id={knobId}
        aria-labelledby={labelId}
        className="relative w-16 h-16 outline-none"
        valueMin={valueMin}
        valueMax={valueMax}
        valueRaw={valueRaw}
        valueRawRoundFn={valueRawRoundFn}
        valueRawDisplayFn={valueRawDisplayFn}
        dragSensitivity={dragSensitivity}
        axis={axis}
        mapTo01={mapTo01}
        mapFrom01={mapFrom01}
        onValueRawChange={setValueRaw}
        {...keyboardControlHandlers}
      >
        <KnobBaseThumb theme={theme} value01={value01} />
      </KnobHeadless>
      <KnobHeadlessOutput htmlFor={knobId}>
        {valueRawDisplayFn(valueRaw)}
      </KnobHeadlessOutput>
    </div>
  );
}
