import { useRef, useEffect, useState as useLocalState, useCallback, useMemo, type ReactNode } from 'react'
import styles from './SegmentedTabs.module.css'

interface TabItem {
  label: ReactNode
  count?: number
  value: string
}

interface SegmentedTabsProps {
  tabs: TabItem[]
  active: string
  onChange: (value: string) => void
  /** Extra element rendered as the last "tab" — participates in indicator animation.
   *  Use `trailingValue` to assign it a value for active state matching. */
  trailing?: ReactNode
  trailingValue?: string
  className?: string
}

export function SegmentedTabs({ tabs, active, onChange, trailing, trailingValue, className }: SegmentedTabsProps) {
  const barRef = useRef<HTMLDivElement>(null)
  const tabRefs = useRef<Map<string, HTMLElement>>(new Map())
  const [indicator, setIndicator] = useLocalState<{ left: number; width: number } | null>(null)

  // Recalculate when labels change (e.g. dynamic date range text)
  const tabsKey = useMemo(() => tabs.map((t) => `${t.value}:${typeof t.label === 'string' ? t.label : ''}`).join('|'), [tabs])

  const updateIndicator = useCallback(() => {
    const bar = barRef.current
    const activeEl = tabRefs.current.get(active)
    if (!bar || !activeEl) return
    const barRect = bar.getBoundingClientRect()
    const elRect = activeEl.getBoundingClientRect()
    setIndicator({
      left: elRect.left - barRect.left,
      width: elRect.width,
    })
  }, [active, tabsKey]) // eslint-disable-line react-hooks/exhaustive-deps

  useEffect(() => {
    const id = requestAnimationFrame(updateIndicator)
    return () => cancelAnimationFrame(id)
  }, [updateIndicator])

  useEffect(() => {
    window.addEventListener('resize', updateIndicator)
    return () => window.removeEventListener('resize', updateIndicator)
  }, [updateIndicator])

  // Observe DOM mutations (e.g. trailing content text changes) to resize indicator
  useEffect(() => {
    const bar = barRef.current
    if (!bar) return
    const observer = new MutationObserver(() => {
      requestAnimationFrame(updateIndicator)
    })
    observer.observe(bar, { childList: true, subtree: true, characterData: true })
    return () => observer.disconnect()
  }, [updateIndicator])

  const trailingActive = trailingValue !== undefined && active === trailingValue

  return (
    <div ref={barRef} className={`${styles.bar} ${className ?? ''}`} role="tablist">
      {indicator && (
        <span
          className={styles.indicator}
          style={{ left: indicator.left, width: indicator.width }}
          aria-hidden="true"
        />
      )}
      {tabs.map((tab) => (
        <button
          key={tab.value}
          ref={(el) => { if (el) tabRefs.current.set(tab.value, el); else tabRefs.current.delete(tab.value) }}
          role="tab"
          aria-selected={tab.value === active}
          className={`${styles.tab} ${tab.value === active ? styles.active : ''}`}
          onClick={() => onChange(tab.value)}
          type="button"
        >
          <span className={styles.label}>{tab.label}</span>
          {tab.count !== undefined && (
            <span className={styles.count}>{tab.count}</span>
          )}
        </button>
      ))}
      {trailing && trailingValue && (
        <div
          ref={(el) => { if (el) tabRefs.current.set(trailingValue, el); else tabRefs.current.delete(trailingValue) }}
          role="tab"
          aria-selected={trailingActive}
          className={`${styles.tab} ${styles.trailingTab} ${trailingActive ? styles.active : ''}`}
        >
          {trailing}
        </div>
      )}
    </div>
  )
}
