"use client";

/**
 * MobileWaterSegmented — an iOS-style segmented control.
 *
 * Mimics UISegmentedControl:
 *   - Rounded 9px outer container in surface-2 (iOS systemGray5).
 *   - White sliding pill behind the selected option.
 *   - iOS spring timing (cubic-bezier(0.32, 0.72, 0, 1)) for the
 *     pill transition.
 *   - Hugs the largest option's natural width when the parent gives
 *     no fixed width — looks balanced for 3-5 short labels.
 *   - 44pt minimum touch target per HIG.
 *
 * Uses a useLayoutEffect ref-measurement pass so the indicator
 * slides smoothly to the correct option when the value changes
 * (including the initial mount and across option-list changes).
 */
import {
  useEffect,
  useLayoutEffect,
  useRef,
  useState,
  type ReactNode,
} from "react";

export type SegmentedOption<V extends string> = {
  value: V;
  label: ReactNode;
  /** Optional badge or icon, rendered inside the segment. */
  badge?: ReactNode;
};

type Props<V extends string> = {
  options: ReadonlyArray<SegmentedOption<V>>;
  value: V;
  onChange: (value: V) => void;
  /** ARIA label for the group. */
  ariaLabel?: string;
  /** Optional fixed height (default 44 — the HIG minimum). */
  height?: number;
  /** Disable the whole control. */
  disabled?: boolean;
};

export function SegmentedControl<V extends string>({
  options,
  value,
  onChange,
  ariaLabel,
  height = 44,
  disabled = false,
}: Props<V>) {
  const containerRef = useRef<HTMLDivElement>(null);
  // Cache {x, width} per option key so the sliding indicator animates
  // even when options aren't measured synchronously (e.g. SSR).
  const [rects, setRects] = useState<Record<string, { x: number; w: number }>>({});

  // Measure on mount and whenever the option set changes.
  useLayoutEffect(() => {
    if (!containerRef.current) return;
    const root = containerRef.current;
    const next: Record<string, { x: number; w: number }> = {};
    options.forEach((opt) => {
      const el = root.querySelector<HTMLButtonElement>(
        `[data-seg-key="${opt.value}"]`,
      );
      if (el) {
        const rootRect = root.getBoundingClientRect();
        const elRect = el.getBoundingClientRect();
        next[opt.value] = { x: elRect.left - rootRect.left, w: elRect.width };
      }
    });
    setRects(next);
  }, [options]);

  // Re-measure on resize so the indicator stays aligned.
  useEffect(() => {
    if (!containerRef.current) return;
    const ro = new ResizeObserver(() => {
      const root = containerRef.current!;
      const next: Record<string, { x: number; w: number }> = {};
      options.forEach((opt) => {
        const el = root.querySelector<HTMLButtonElement>(
          `[data-seg-key="${opt.value}"]`,
        );
        if (el) {
          const rootRect = root.getBoundingClientRect();
          const elRect = el.getBoundingClientRect();
          next[opt.value] = { x: elRect.left - rootRect.left, w: elRect.width };
        }
      });
      setRects(next);
    });
    ro.observe(containerRef.current);
    return () => ro.disconnect();
  }, [options]);

  const active = rects[value];

  return (
    <div
      ref={containerRef}
      role="tablist"
      aria-label={ariaLabel}
      className="relative inline-flex w-full items-stretch rounded-[10px] bg-[rgba(120,120,128,0.12)] p-[2px]"
      style={{
        height,
        opacity: disabled ? 0.5 : 1,
      }}
    >
      {/* Sliding indicator. 4px of inset (2px container padding + 2px
       *  visual breathing room) gives it the iOS look without
       *  feeling cramped. */}
      {active && (
        <div
          aria-hidden
          className="absolute top-[2px] bottom-[2px] rounded-[8px] bg-white"
          style={{
            transform: `translateX(${active.x - 2}px)`,
            width: active.w,
            boxShadow:
              "0 1px 1px rgba(0,0,0,0.04), 0 2px 6px rgba(0,0,0,0.06), inset 0 0 0 0.5px rgba(0,0,0,0.04)",
            transition:
              "transform 320ms cubic-bezier(0.32, 0.72, 0, 1), width 320ms cubic-bezier(0.32, 0.72, 0, 1)",
          }}
        />
      )}
      {options.map((opt) => {
        const selected = opt.value === value;
        return (
          <button
            key={opt.value}
            type="button"
            role="tab"
            aria-selected={selected}
            data-seg-key={opt.value}
            disabled={disabled}
            onClick={() => onChange(opt.value)}
            className={[
              "relative z-10 flex-1 select-none px-2 text-[15px] font-semibold leading-none",
              "flex items-center justify-center gap-1.5",
              "rounded-[8px] active:opacity-80",
              selected ? "text-[#1d1d1f]" : "text-[rgba(60,60,67,0.6)]",
            ].join(" ")}
            style={{
              minHeight: 44,
              transition: "color 200ms cubic-bezier(0.32, 0.72, 0, 1)",
            }}
          >
            <span className="truncate">{opt.label}</span>
            {opt.badge != null && (
              <span className="text-[11px] font-bold leading-none rounded-full bg-[rgba(120,120,128,0.16)] text-[#3c3c43] px-1.5 py-0.5">
                {opt.badge}
              </span>
            )}
          </button>
        );
      })}
    </div>
  );
}

export default SegmentedControl;