import { useCallback, useRef, useState } from 'react';
import type { CSSProperties, KeyboardEvent, ReactNode } from 'react';
import { cx } from '../../utils/cx';
import { useFallbackId } from '../../utils/useId';
import './Tabs.css';

export interface TabItem {
  /** Stable identifier — this is the value reported by `onValueChange`. */
  id: string;
  label: ReactNode;
  /** Panel contents. Omit to render only the tab strip. */
  content?: ReactNode;
  disabled?: boolean;
  /** Trailing element beside the label, typically a count or Badge. */
  badge?: ReactNode;
}

export interface TabsProps {
  items: TabItem[];
  /** Controlled selection. Pair with `onValueChange`. */
  value?: string;
  /** Initial selection when uncontrolled. Defaults to the first enabled tab. */
  defaultValue?: string;
  onValueChange?: (id: string) => void;
  variant?: 'underline' | 'pill';
  /** Distributes tabs evenly across the full width. */
  fullWidth?: boolean;
  className?: string;
  style?: CSSProperties;
}

/**
 * Tabbed navigation with full keyboard support: arrow keys move and select,
 * Home/End jump to the ends, disabled tabs are skipped.
 */
export function Tabs({
  items,
  value,
  defaultValue,
  onValueChange,
  variant = 'underline',
  fullWidth = false,
  className,
  style,
}: TabsProps) {
  const baseId = useFallbackId();
  const firstEnabled = items.find((item) => !item.disabled)?.id;
  const [internalValue, setInternalValue] = useState(defaultValue ?? firstEnabled ?? '');
  const tabRefs = useRef<Record<string, HTMLButtonElement | null>>({});

  const isControlled = value !== undefined;
  const activeId = isControlled ? value : internalValue;

  const select = useCallback(
    (id: string) => {
      if (!isControlled) setInternalValue(id);
      onValueChange?.(id);
    },
    [isControlled, onValueChange],
  );

  const moveFocus = useCallback(
    (fromIndex: number, step: number) => {
      const count = items.length;
      for (let offset = 1; offset <= count; offset += 1) {
        const next = items[(fromIndex + step * offset + count * count) % count];
        if (next && !next.disabled) {
          select(next.id);
          tabRefs.current[next.id]?.focus();
          return;
        }
      }
    },
    [items, select],
  );

  const onKeyDown = (event: KeyboardEvent<HTMLButtonElement>, index: number) => {
    switch (event.key) {
      case 'ArrowRight':
        event.preventDefault();
        moveFocus(index, 1);
        break;
      case 'ArrowLeft':
        event.preventDefault();
        moveFocus(index, -1);
        break;
      case 'Home':
        event.preventDefault();
        moveFocus(-1, 1);
        break;
      case 'End':
        event.preventDefault();
        moveFocus(items.length, -1);
        break;
      default:
        break;
    }
  };

  const activeItem = items.find((item) => item.id === activeId);

  return (
    <div className={cx('ds-tabs', `ds-tabs--${variant}`, className)} style={style}>
      <div
        role="tablist"
        className={cx('ds-tabs__list', fullWidth && 'ds-tabs__list--full')}
      >
        {items.map((item, index) => {
          const selected = item.id === activeId;
          return (
            <button
              key={item.id}
              ref={(node) => {
                tabRefs.current[item.id] = node;
              }}
              type="button"
              role="tab"
              id={`${baseId}-tab-${item.id}`}
              aria-controls={item.content != null ? `${baseId}-panel-${item.id}` : undefined}
              aria-selected={selected}
              tabIndex={selected ? 0 : -1}
              disabled={item.disabled}
              className={cx('ds-tabs__tab', selected && 'ds-tabs__tab--selected')}
              onClick={() => select(item.id)}
              onKeyDown={(event) => onKeyDown(event, index)}
            >
              <span className="ds-tabs__tab-label">{item.label}</span>
              {item.badge != null && <span className="ds-tabs__tab-badge">{item.badge}</span>}
            </button>
          );
        })}
      </div>
      {activeItem?.content != null && (
        <div
          role="tabpanel"
          id={`${baseId}-panel-${activeItem.id}`}
          aria-labelledby={`${baseId}-tab-${activeItem.id}`}
          tabIndex={0}
          className="ds-tabs__panel"
        >
          {activeItem.content}
        </div>
      )}
    </div>
  );
}
