'use client'

import {
  Children,
  createContext,
  forwardRef,
  type JSX,
  KeyboardEvent,
  ReactNode,
  Ref,
  useContext,
  useEffect,
  useRef,
} from 'react'

import type { TTagSkin } from 'shared-types'

import { PktIcon } from '../icon/Icon'
import { PktTabItem } from './TabItem'

// Context for passing tab navigation logic to children
interface ITabsContext {
  arrowNav: boolean
  registerTabRef: (
    index: number,
    el: HTMLAnchorElement | HTMLButtonElement | null,
    disabled?: boolean,
  ) => void
  handleKeyPress: (index: number, event: KeyboardEvent<HTMLAnchorElement | HTMLButtonElement>) => void
  selectTab: (index: number) => void
}

const TabsContext = createContext<ITabsContext | null>(null)

export const useTabsContext = () => {
  const context = useContext(TabsContext)
  if (!context) {
    throw new Error('TabItem must be used within a Tabs component')
  }
  return context
}

export interface IPktTab {
  text: string
  href?: string
  action?: (index: number) => void
  disabled?: boolean
  icon?: string
  controls?: string
  tag?: {
    text: string
    skin: TTagSkin | undefined
  }
  active?: boolean
}

export interface IPktTabs {
  arrowNav?: boolean
  disableArrowNav?: boolean
  separatorIconName?: string
  separatorIconPath?: string
  tabs?: IPktTab[]
  onTabSelected?: (index: number) => void
  children?: ReactNode
}

export const PktTabs = forwardRef(
  (
    {
      arrowNav = true,
      disableArrowNav = false,
      separatorIconName,
      separatorIconPath,
      tabs,
      onTabSelected,
      children,
    }: IPktTabs,
    ref: Ref<HTMLDivElement>,
  ): JSX.Element => {
    const tabRefs = useRef<Array<HTMLAnchorElement | HTMLButtonElement | null>>([])
    const disabledMap = useRef<Record<number, boolean>>({})

    const useArrowNav = arrowNav && !disableArrowNav

    // Determine if we're using children or tabs array
    const childItems = Children.toArray(children)
    const hasChildren = childItems.length > 0
    const tabCount = hasChildren ? childItems.length : tabs?.length || 0
    const hasSeparator = !!(separatorIconName || separatorIconPath)

    useEffect(() => {
      tabRefs.current = tabRefs.current.slice(0, tabCount)
      Object.keys(disabledMap.current).forEach((key) => {
        const index = Number(key)
        if (index >= tabCount) delete disabledMap.current[index]
      })
    }, [tabCount])

    const isTabDisabled = (index: number): boolean => {
      if (tabs) return !!tabs[index]?.disabled
      return !!disabledMap.current[index]
    }

    const selectTab = (index: number): void => {
      if (isTabDisabled(index)) return
      const tab = tabs?.[index]
      if (tab?.action) {
        tab.action(index)
      }
      if (onTabSelected) onTabSelected(index)
    }

    const findEnabledIndex = (startIndex: number, direction: -1 | 1): number | null => {
      let current = startIndex + direction

      while (current >= 0 && current < tabCount) {
        if (!isTabDisabled(current)) return current
        current += direction
      }

      return null
    }

    const handleKeyPress = (index: number, event: KeyboardEvent<HTMLAnchorElement | HTMLButtonElement>) => {
      if (!useArrowNav) return

      if (event.key === 'ArrowLeft') {
        event.preventDefault()
        const previousEnabled = findEnabledIndex(index, -1)
        if (previousEnabled !== null) tabRefs.current[previousEnabled]?.focus()
      }

      if (event.key === 'ArrowRight') {
        event.preventDefault()
        const nextEnabled = findEnabledIndex(index, 1)
        if (nextEnabled !== null) tabRefs.current[nextEnabled]?.focus()
      }

      if (event.key === 'Enter' || event.key === ' ' || event.key === 'Spacebar' || event.key === 'ArrowDown') {
        event.preventDefault()
        if (!isTabDisabled(index)) {
          selectTab(index)
        }
      }
    }

    const registerTabRef = (
      index: number,
      el: HTMLAnchorElement | HTMLButtonElement | null,
      disabled = false,
    ) => {
      tabRefs.current[index] = el
      disabledMap.current[index] = disabled
    }

    const renderSeparator = (key: string) => (
      <span className="pkt-tabs__separator" aria-hidden="true" role="presentation" key={key}>
        {separatorIconPath ? (
          <img src={separatorIconPath} alt="" aria-hidden="true" />
        ) : separatorIconName ? (
          <PktIcon name={separatorIconName} className="pkt-tabs__separator-icon" />
        ) : null}
      </span>
    )

    const withSeparators = (items: ReactNode[]) => {
      if (!hasSeparator || items.length <= 1) return items
      return items.flatMap((item, index) =>
        index < items.length - 1 ? [item, renderSeparator(`separator-${index}`)] : [item],
      )
    }

    const tabItems = tabs?.map((tab, index) => (
      <PktTabItem
        key={index}
        active={tab.disabled ? false : tab.active}
        disabled={tab.disabled}
        href={tab.href}
        icon={tab.icon}
        controls={tab.controls}
        tag={tab.tag?.text}
        tagSkin={tab.tag?.skin}
        index={index}
      >
        {tab.text}
      </PktTabItem>
    ))

    const tabsClasses = ['pkt-tabs', hasSeparator && 'pkt-tabs--with-separator'].filter(Boolean).join(' ')
    const renderedTabs = withSeparators((hasChildren ? childItems : tabItems || []) as ReactNode[])

    return (
      <TabsContext.Provider value={{ arrowNav: useArrowNav, registerTabRef, handleKeyPress, selectTab }}>
        <div className={tabsClasses} ref={ref}>
          <div className="pkt-tabs__list" role={useArrowNav ? 'tablist' : 'navigation'}>
            {renderedTabs}
          </div>
        </div>
      </TabsContext.Provider>
    )
  },
)

export { PktTabItem } from './TabItem'

PktTabs.displayName = 'PktTabs'
