// @design-system: primitives/SegmentedControl
/**
 * SegmentedControl - an accessible radiogroup-style segmented button control.
 *
 * Keyboard: Tab into the group focuses the selected option.
 * Arrow keys move selection (Left/Right, RTL-aware).
 * Each option has role="radio" + aria-checked.
 *
 * @example
 * ```tsx
 * <SegmentedControl
 *   aria-label="Text size"
 *   value="M"
 *   onChange={setScale}
 *   options={[
 *     { value: 'S', label: 'S' },
 *     { value: 'M', label: 'M' },
 *     { value: 'L', label: 'L' },
 *   ]}
 * />
 * ```
 */

'use client';

import { forwardRef, useRef, useCallback, useLayoutEffect, useState } from 'react';
import { cn } from '@/lib/cn';
import { segmentedControlVariants, segmentedOptionVariants } from './variants';

export interface SegmentedControlOption {
  /** The underlying value. */
  value: string;
  /** Display label for the option. */
  label: string;
  /** Whether this option is disabled. */
  disabled?: boolean;
}

export interface SegmentedControlProps {
  /** Currently selected value. */
  value: string;
  /** Called when the user selects a new option. */
  onChange: (value: string) => void;
  /** The list of options to display. */
  options: SegmentedControlOption[];
  /**
   * Accessible label for the radiogroup container.
   * Required — TS enforces this via the type (no `aria-label?`).
   */
  'aria-label': string;
  /** Visual + touch target size. */
  size?: 'sm' | 'md';
  /** Additional class names applied to the container. */
  className?: string;
}

/**
 * SegmentedControl — horizontal radiogroup with tokenized styling.
 *
 * a11y:
 * - Container: `role="radiogroup"` + `aria-label`
 * - Options: `role="radio"` + `aria-checked` + `tabIndex` roving
 * - Arrow keys cycle selection; RTL-aware (reads `dir` from the DOM)
 */
export const SegmentedControl = forwardRef<HTMLDivElement, SegmentedControlProps>(
  function SegmentedControl(
    { value, onChange, options, 'aria-label': ariaLabel, size = 'md', className },
    ref,
  ) {
    const containerRef = useRef<HTMLDivElement>(null);
    const [indicatorStyle, setIndicatorStyle] = useState<{
      width: number;
      transform: string;
      opacity: number;
    }>({
      width: 0,
      transform: 'translateX(0px)',
      opacity: 0,
    });

    // Resolve ref so we can also access internally
    const setRef = useCallback(
      (node: HTMLDivElement | null) => {
        (containerRef as React.RefObject<HTMLDivElement | null>).current = node;
        if (typeof ref === 'function') ref(node);
        else if (ref) (ref as React.RefObject<HTMLDivElement | null>).current = node;
      },
      [ref],
    );

    useLayoutEffect(() => {
      const container = containerRef.current;
      if (!container) return;

      const updateIndicator = () => {
        const selected = container.querySelector<HTMLButtonElement>(
          `button[role="radio"][data-value="${CSS.escape(value)}"]`,
        );

        if (!selected) {
          setIndicatorStyle((current) => ({ ...current, opacity: 0 }));
          return;
        }

        const containerRect = container.getBoundingClientRect();
        const selectedRect = selected.getBoundingClientRect();
        const isRtl = getComputedStyle(container).direction === 'rtl';
        const offsetFromStart = isRtl
          ? containerRect.x + containerRect.width - selectedRect.x - selectedRect.width
          : selectedRect.x - containerRect.x;

        setIndicatorStyle({
          width: selectedRect.width,
          transform: `translateX(${isRtl ? -offsetFromStart : offsetFromStart}px)`,
          opacity: 1,
        });
      };

      updateIndicator();
      if (typeof ResizeObserver === 'undefined') return;
      const observer = new ResizeObserver(updateIndicator);
      observer.observe(container);
      return () => observer.disconnect();
    }, [options, value]);

    const handleKeyDown = useCallback(
      (e: React.KeyboardEvent<HTMLButtonElement>, currentIndex: number) => {
        const enabledOptions = options.filter((o) => !o.disabled);
        if (enabledOptions.length < 2) return;

        // Detect RTL from the container's computed direction
        const dir = containerRef.current ? getComputedStyle(containerRef.current).direction : 'ltr';
        const isRtl = dir === 'rtl';

        let nextIndex = -1;

        // ArrowRight in LTR = forward; in RTL = backward
        if ((e.key === 'ArrowRight' && !isRtl) || (e.key === 'ArrowLeft' && isRtl)) {
          e.preventDefault();
          const enabledIdx = enabledOptions.findIndex(
            (o) => o.value === options[currentIndex]?.value,
          );
          nextIndex = (enabledIdx + 1) % enabledOptions.length;
        } else if ((e.key === 'ArrowLeft' && !isRtl) || (e.key === 'ArrowRight' && isRtl)) {
          e.preventDefault();
          const enabledIdx = enabledOptions.findIndex(
            (o) => o.value === options[currentIndex]?.value,
          );
          nextIndex = (enabledIdx - 1 + enabledOptions.length) % enabledOptions.length;
        }

        if (nextIndex !== -1) {
          const next = enabledOptions[nextIndex];
          if (next) {
            onChange(next.value);
            // Move DOM focus to the newly selected button
            const buttons =
              containerRef.current?.querySelectorAll<HTMLButtonElement>('button[role="radio"]');
            if (buttons) {
              const targetBtn = Array.from(buttons).find(
                (btn) => btn.dataset['value'] === next.value,
              );
              targetBtn?.focus();
            }
          }
        }
      },
      [options, onChange],
    );

    return (
      <div
        ref={setRef}
        role="radiogroup"
        aria-label={ariaLabel}
        className={cn(segmentedControlVariants({ size }), className)}
      >
        <span
          aria-hidden="true"
          data-testid="segmented-indicator"
          className={cn(
            'bg-surface-base border-border-default pointer-events-none absolute inset-y-0.5 start-0 rounded shadow-sm transition-all duration-200 motion-reduce:transition-none',
          )}
          style={indicatorStyle}
        />
        {options.map((opt, idx) => {
          const isSelected = opt.value === value;
          return (
            <button
              key={opt.value}
              type="button"
              role="radio"
              aria-checked={isSelected}
              aria-disabled={opt.disabled}
              disabled={opt.disabled}
              data-value={opt.value}
              // Roving tabIndex: only selected (or first if none selected) gets tabIndex=0
              tabIndex={isSelected ? 0 : -1}
              onClick={() => {
                if (!opt.disabled) onChange(opt.value);
              }}
              onKeyDown={(e) => handleKeyDown(e, idx)}
              className={cn(segmentedOptionVariants({ size, selected: isSelected }))}
            >
              {opt.label}
            </button>
          );
        })}
      </div>
    );
  },
);

SegmentedControl.displayName = 'SegmentedControl';
