import React from 'react'

import styles from './_desktop-router-tabs.module.scss'
import { useDynamicTabWidths } from '../../../../hooks/useDynamicTabWidths/useDynamicTabWidths'

const { useRef, useLayoutEffect } = React

const activeClassName = 'active'
const customClassName = styles.routertabsLink

// Type definition for NavLink props
interface NavLinkProps {
  className?: string
  to?: string
  [key: string]: any
}

// Helper type that allows us to safely work with JSX elements
type ReactElementWithProps = React.ReactElement<NavLinkProps>

export type DesktopRouterTabsProps = {
  /** Multiple children. Typically in the form of NavLink components */
  children: React.ReactNode[]
  /** Determines the style of the tabs. If true, the subtabs style will be applied. */
  subtabs?: boolean
  /** Current path from the router */
  currentPath: string
  /** Refresh router tab animation */
  refreshRouterTabs?: boolean
  /** Optional prop to add a test id to the DesktopRouterTabs for QA testing */
  qaTestId?: string
}

export default function DesktopRouterTabs({
  children,
  subtabs = false,
  currentPath,
  refreshRouterTabs,
  qaTestId,
}: DesktopRouterTabsProps) {
  const activeBarRef = useRef<HTMLDivElement | null>(null)
  const bottomBarRef = useRef<HTMLDivElement | null>(null)
  const navlinkContainerRef = useRef<HTMLDivElement | null>(null)
  const previousAnimationRef = useRef<Animation | null>(null)

  /**
   * Dynamic tab width measurement hook.
   * Monitors tab content changes and triggers realignment when widths change.
   * See useDynamicTabWidths for implementation details.
   */
  const { measurementKey: tabsMeasurementKey } = useDynamicTabWidths({
    containerRef: subtabs ? bottomBarRef : navlinkContainerRef,
    tabClassName: customClassName,
    enabled: true,
  })

  // Count only valid React elements
  const numberOfChildrenNodes = React.Children.toArray(children).filter(
    (child) => React.isValidElement(child),
  ).length

  useLayoutEffect(() => {
    // every rerender, check to see if we need to update the location of the active bar underneath the NavLink
    const childrenNodes = Array.from(
      (subtabs
        ? bottomBarRef
        : navlinkContainerRef
      ).current?.getElementsByClassName(customClassName) || [],
    )

    const active = childrenNodes.find((ref) =>
      ref?.classList.contains(activeClassName),
    )

    function animateElement() {
      if (active && activeBarRef.current && bottomBarRef.current) {
        const { left: destinationLeft, width: destinationWidth } =
          active.getBoundingClientRect()
        const { left: firstBarLeft, width: firstBarWidth } =
          activeBarRef.current.getBoundingClientRect()
        const { left: bottomBarLeft } =
          bottomBarRef.current.getBoundingClientRect()

        activeBarRef.current.style.transition = ''
        activeBarRef.current.style.left = `${destinationLeft - bottomBarLeft}px`
        activeBarRef.current.style.width = `${destinationWidth}px`

        const { left: lastBarLeft, width: lastBarWidth } =
          activeBarRef.current.getBoundingClientRect()

        const deltaX = firstBarLeft - lastBarLeft
        const deltaW = firstBarWidth / lastBarWidth

        previousAnimationRef.current = activeBarRef.current.animate(
          [
            { transform: `translateX(${deltaX}px) scaleX(${deltaW})` },
            { transform: 'none' },
          ],
          {
            duration: 250,
            easing: 'ease-in-out',
          },
        )
      }
    }

    if (childrenNodes.length && activeBarRef.current) {
      active?.classList?.add(styles.routertabsLinkActive)
      if (active) {
        if (
          previousAnimationRef.current &&
          previousAnimationRef.current.playState !== 'finished'
        ) {
          previousAnimationRef.current.onfinish = animateElement
        } else {
          animateElement()
        }
      }
    }
  }, [
    currentPath,
    subtabs,
    numberOfChildrenNodes,
    refreshRouterTabs,
    tabsMeasurementKey, // Re-align active bar when tab measurements change
    activeBarRef,
    bottomBarRef,
    navlinkContainerRef,
    previousAnimationRef,
  ])

  return (
    <div qa-test-id={qaTestId}>
      <nav
        className={`${styles.routertabsNavContainer} ${
          subtabs ? styles.routertabsSubtabs : ''
        }`.trim()}
        ref={subtabs ? bottomBarRef : navlinkContainerRef}
      >
        {React.Children.toArray(children)
          // Cast to more specific array type after filtering
          .filter(React.isValidElement)
          .map((child) => {
            // Cast to our helper type
            const element = child as ReactElementWithProps

            // Merge the classNames
            const mergedClassName =
              `${element.props.className || ''} ${customClassName}`.trim()

            // Use proper typing for cloneElement
            return React.cloneElement<NavLinkProps>(element, {
              className: mergedClassName,
            })
          })}
        {subtabs ? (
          <div
            className={styles.routertabsSubtabsActive}
            ref={activeBarRef}
            style={{
              width: '0px',
            }}
          />
        ) : null}
      </nav>
      {!subtabs ? (
        <div className={styles.routertabsBottomBar} ref={bottomBarRef}>
          <div
            className={styles.routertabsBottomBarActive}
            ref={activeBarRef}
            style={{
              width: '0px',
            }}
          />
        </div>
      ) : null}
    </div>
  )
}
