import { useCallback, useId, type ReactNode } from 'react'
import { formatInteger } from '@/utils/format'

export interface SectionTab<T extends string> {
  id: T
  label: string
  count?: number
}

interface SectionTabsProps<T extends string> {
  tabs: SectionTab<T>[]
  activeTab: T
  onChange: (tab: T) => void
  className?: string
  idPrefix?: string
  ariaLabel?: string
}

export function sectionTabPanelProps<T extends string>(
  idPrefix: string,
  tabId: T,
  activeTab: T,
) {
  return {
    id: `${idPrefix}-panel-${tabId}`,
    role: 'tabpanel' as const,
    'aria-labelledby': `${idPrefix}-tab-${tabId}`,
    hidden: activeTab !== tabId,
  }
}

interface TabPanelProps<T extends string> {
  idPrefix: string
  tabId: T
  activeTab: T
  children: ReactNode
  className?: string
}

/** Renders tab content only while active to keep pages short and avoid hidden-panel scroll. */
export function TabPanel<T extends string>({
  idPrefix,
  tabId,
  activeTab,
  children,
  className = '',
}: TabPanelProps<T>) {
  if (activeTab !== tabId) {
    return null
  }

  return (
    <div {...sectionTabPanelProps(idPrefix, tabId, activeTab)} className={className}>
      {children}
    </div>
  )
}

export default function SectionTabs<T extends string>({
  tabs,
  activeTab,
  onChange,
  className = '',
  idPrefix,
  ariaLabel = 'Sections',
}: SectionTabsProps<T>) {
  const generatedId = useId().replace(/:/g, '')
  const tabListPrefix = idPrefix || generatedId

  const focusTab = useCallback(
    (tabId: T) => {
      const element = document.getElementById(`${tabListPrefix}-tab-${tabId}`)
      element?.focus()
    },
    [tabListPrefix],
  )

  const handleKeyDown = useCallback(
    (event: React.KeyboardEvent<HTMLDivElement>) => {
      const currentIndex = tabs.findIndex((tab) => tab.id === activeTab)
      if (currentIndex < 0) {
        return
      }

      let nextIndex = currentIndex

      if (event.key === 'ArrowRight') {
        nextIndex = (currentIndex + 1) % tabs.length
      } else if (event.key === 'ArrowLeft') {
        nextIndex = (currentIndex - 1 + tabs.length) % tabs.length
      } else if (event.key === 'Home') {
        nextIndex = 0
      } else if (event.key === 'End') {
        nextIndex = tabs.length - 1
      } else {
        return
      }

      event.preventDefault()
      const nextTab = tabs[nextIndex]
      onChange(nextTab.id)
      focusTab(nextTab.id)
    },
    [activeTab, focusTab, onChange, tabs],
  )

  return (
    <div
      className={`sticky top-0 z-20 border-b border-gray-200 bg-white/95 py-2 backdrop-blur dark:border-gray-800 dark:bg-gray-950/95 ${className}`}
    >
      <div
        role="tablist"
        aria-label={ariaLabel}
        className="flex gap-2 overflow-x-auto"
        onKeyDown={handleKeyDown}
      >
        {tabs.map((tab) => {
          const isActive = activeTab === tab.id
          const accessibleLabel =
            typeof tab.count === 'number'
              ? `${tab.label} (${formatInteger(tab.count)})`
              : tab.label

          return (
            <button
              key={tab.id}
              id={`${tabListPrefix}-tab-${tab.id}`}
              type="button"
              role="tab"
              aria-selected={isActive}
              aria-controls={`${tabListPrefix}-panel-${tab.id}`}
              aria-label={accessibleLabel}
              tabIndex={isActive ? 0 : -1}
              onClick={() => onChange(tab.id)}
              className={
                isActive
                  ? 'whitespace-nowrap rounded-lg bg-primary-600 px-3 py-2 text-sm font-semibold text-white'
                  : 'whitespace-nowrap rounded-lg border border-gray-300 px-3 py-2 text-sm font-medium text-gray-700 transition hover:border-primary-400 hover:text-primary-700 dark:border-gray-700 dark:text-gray-300 dark:hover:text-primary-300'
              }
            >
              {tab.label}
              {typeof tab.count === 'number' ? (
                <span
                  aria-hidden="true"
                  className={isActive ? 'ml-2 text-primary-100' : 'ml-2 text-gray-500 dark:text-gray-400'}
                >
                  {formatInteger(tab.count)}
                </span>
              ) : null}
            </button>
          )
        })}
      </div>
    </div>
  )
}
