import { useRef } from 'react'
import { makeStyles, mergeClasses, tokens } from '@fluentui/react-components'
import { useFocusStyles } from './focusRing'
import { ICON } from './tokens'

export interface SegmentOption<T extends string> {
  value: T
  label: string
  /** optional leading icon (used by the sidebar theme switch) */
  icon?: React.JSX.Element
}

const useStyles = makeStyles({
  group: {
    display: 'inline-flex',
    width: 'fit-content',
    border: `1px solid ${tokens.colorNeutralStroke1}`,
    borderRadius: tokens.borderRadiusMedium,
    overflow: 'hidden'
  },
  // Full-width variant: segments split the available width (the sidebar style).
  fitted: {
    display: 'flex',
    width: '100%'
  },
  segment: {
    appearance: 'none',
    border: 'none',
    backgroundColor: 'transparent',
    color: tokens.colorNeutralForeground2,
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    gap: '5px',
    padding: '7px 16px',
    fontSize: tokens.fontSizeBase300,
    fontFamily: tokens.fontFamilyBase,
    cursor: 'pointer',
    ':hover': {
      backgroundColor: tokens.colorNeutralBackground1Hover
    }
  },
  segmentFitted: {
    flexGrow: 1,
    flexBasis: 0,
    padding: '7px 4px',
    fontSize: tokens.fontSizeBase200
  },
  segmentActive: {
    backgroundColor: tokens.colorBrandBackground,
    color: tokens.colorNeutralForegroundOnBrand,
    fontWeight: tokens.fontWeightSemibold,
    ':hover': {
      backgroundColor: tokens.colorBrandBackgroundHover
    },
    // Under Windows High Contrast the brand background is flattened to the system
    // canvas, so the checked segment would be indistinguishable from the others
    // (W18). Paint it with the system Highlight pair so the selection stays visible.
    '@media (forced-colors: active)': {
      backgroundColor: 'Highlight',
      color: 'HighlightText',
      forcedColorAdjust: 'none'
    }
  },
  icon: {
    display: 'flex',
    fontSize: `${ICON.inline}px`,
    flexShrink: 0
  }
})

/**
 * One shared segmented control (UI14) replacing the two hand-rolled versions —
 * the DownloadBar's Video/Audio kind toggle and the Sidebar's Light/Dark/Auto
 * theme switch. Renders an ARIA radiogroup with roving-tabindex arrow-key
 * navigation (UI30) and the shared focus ring (UI29). `fitted` makes the segments
 * split the full width (sidebar); the default is fit-content (download bar).
 *
 * Active treatment is solid brand — the app's one rule for *toggles* (a compact
 * set where the chosen option should read as pressed). This is deliberately
 * distinct from the brand-*tint* used for *selection within a list* (the Sidebar
 * nav item, the CommandPalette active option): one active treatment per control
 * class (UI20).
 */
export function SegmentedControl<T extends string>({
  value,
  options,
  onChange,
  ariaLabel,
  fitted = false
}: {
  value: T
  options: SegmentOption<T>[]
  onChange: (value: T) => void
  ariaLabel: string
  fitted?: boolean
}): React.JSX.Element {
  const styles = useStyles()
  const focus = useFocusStyles()
  const refs = useRef<(HTMLButtonElement | null)[]>([])

  function onKeyDown(e: React.KeyboardEvent, index: number): void {
    let next = -1
    if (e.key === 'ArrowRight' || e.key === 'ArrowDown') next = (index + 1) % options.length
    else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp')
      next = (index - 1 + options.length) % options.length
    else if (e.key === 'Home') next = 0
    else if (e.key === 'End') next = options.length - 1
    else return
    const opt = options[next]
    if (!opt) return
    e.preventDefault()
    onChange(opt.value)
    refs.current[next]?.focus()
  }

  return (
    <div
      className={mergeClasses(styles.group, fitted && styles.fitted)}
      role="radiogroup"
      aria-label={ariaLabel}
    >
      {options.map((opt, i) => {
        const on = opt.value === value
        return (
          <button
            key={opt.value}
            ref={(el) => {
              refs.current[i] = el
            }}
            type="button"
            role="radio"
            aria-checked={on}
            // Roving tabindex: only the selected segment is a tab stop; arrow keys
            // move within the group, as a radiogroup is expected to behave.
            tabIndex={on ? 0 : -1}
            className={mergeClasses(
              styles.segment,
              fitted && styles.segmentFitted,
              on && styles.segmentActive,
              focus.focusRing
            )}
            onClick={() => onChange(opt.value)}
            onKeyDown={(e) => onKeyDown(e, i)}
          >
            {opt.icon && <span className={styles.icon}>{opt.icon}</span>}
            {opt.label}
          </button>
        )
      })}
    </div>
  )
}
