'use client'

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

import { PktTabItem } from './TabItem'

export type TSkin = 'blue' | 'green' | 'red' | 'beige' | 'yellow' | 'grey' | 'gray' | 'blue-light'

// 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: TSkin | undefined
  }
  active?: boolean
}

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

export const PktTabs = forwardRef(
  (
    { arrowNav = true, disableArrowNav = false, 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 hasChildren = children && Children.count(children) > 0
    const tabCount = hasChildren ? Children.count(children) : tabs?.length || 0

    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
    }

    // If tabs as prop instead of children
    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>
    ))

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

export { PktTabItem } from './TabItem'

PktTabs.displayName = 'PktTabs'
