'use client'

import { createContext, useContext, type ComponentProps } from 'react'
import flattenChildren from 'react-keyed-flatten-children'

import type { GDSComponentProps } from '@graphprotocol/gds-css'
import { CheckIcon } from '@graphprotocol/gds-react/icons'

import { useCSSPropsPolyfill, useGDS } from '../hooks/index.ts'
import { cn, getCSSPropsAttributes } from '../utils/index.ts'
import { StepperMeta } from './Stepper.meta.ts'
import { Tag } from './Tag.tsx'

export interface StepperProps extends ComponentProps<'div'>, GDSComponentProps<typeof StepperMeta> {
  /** Defaults to the number of `Stepper.Step` children, or `1` if there are none. */
  count?: number | undefined
  currentIndex: number
}

export const StepperRoot = ({
  ref: passedRef,
  count = 1,
  currentIndex: passedCurrentIndex,
  labelPosition,
  className,
  style,
  children,
  ...props
}: StepperProps) => {
  useGDS()

  const [cssPropsPolyfillPassedRef, cssPropsPolyfillAttributes] = useCSSPropsPolyfill(
    StepperMeta,
    {
      labelPosition,
    },
    { ref: passedRef },
  )

  const childrenArray = children
    ? flattenChildren(children)
    : Array.from({ length: Math.min(Math.max(1, count), 16) }, (_, index) => (
        <StepperStep key={index} />
      ))
  const currentIndex = Math.min(
    Math.max(
      Number.isInteger(passedCurrentIndex) ? passedCurrentIndex : Math.round(passedCurrentIndex),
      0,
    ),
    childrenArray.length - 1,
  )

  return (
    <div
      ref={cssPropsPolyfillPassedRef}
      className={cn('gds-stepper root-block i:h-max', className)}
      {...getCSSPropsAttributes(StepperMeta, { labelPosition }, style)}
      {...cssPropsPolyfillAttributes}
      {...props}
    >
      <ol className="flex gap-1">
        {childrenArray.map((child, childIndex) => (
          <StepperStepContext.Provider key={childIndex} value={{ index: childIndex, currentIndex }}>
            {child}
          </StepperStepContext.Provider>
        ))}
      </ol>
    </div>
  )
}
StepperRoot.displayName = 'Stepper'

const StepperStepContext = createContext({
  index: 0,
  currentIndex: 0,
})

export interface StepperStepProps extends ComponentProps<'li'> {}

export const StepperStep = ({ className, children, ...props }: StepperStepProps) => {
  const { index, currentIndex } = useContext(StepperStepContext)
  const isCurrent = index === currentIndex
  const isComplete = index < currentIndex

  return (
    <li
      aria-current={isCurrent ? 'step' : undefined}
      data-status={isComplete ? 'complete' : isCurrent ? 'current' : 'incomplete'}
      className={cn(
        `group/stepper-step root-flex flex-1 flex-col gap-2
        @prop-label-position-bottom/stepper:flex-col-reverse
        u:min-w-4`,
        className,
      )}
      {...props}
    >
      {children ? (
        <span
          className={`
            flex items-center gap-1 px-1
            @prop-label-position-hidden/stepper:sr-only
          `}
        >
          <Tag
            variant="elevated"
            size="xsmall"
            aria-hidden
            className={`
              shrink-0 var-[padding=0]
              group-data-[status=current]/stepper-step:prop-variant-brand
            `}
          >
            {isComplete ? <CheckIcon alt="" size={2.5} /> : index + 1}
          </Tag>
          <span
            className={`
              truncate text-12 transition
              group-data-[status=complete]/stepper-step:text-strong
              group-data-[status=current]/stepper-step:text-default
              group-data-[status=incomplete]/stepper-step:text-elevated
            `}
          >
            {children}
          </span>
        </span>
      ) : (
        <span className="sr-only">
          Step {index}
          {isComplete ? ' (Completed)' : ''}
        </span>
      )}
      <span className="block h-0.5 overflow-clip rounded-full rtl:-scale-x-100">
        <span
          className={`
            absolute inset-y-0 left-0 flex w-[205%] animate-translate-x-from-0 animate-translate-x-to-0 transition duration-300 animate-duration-300
            group-has-[~[data-status=current]]/stepper-step:transition-none
            group-data-[status=current]/stepper-step:animate-translate-x-from-[-51%]
            group-data-[status=incomplete]/stepper-step:animate-translate-x-from-[-51%]
            group-data-[status=incomplete]/stepper-step:animate-translate-x-to-[-51%]
            group-data-[status=incomplete]/stepper-step:translate-x-[-51%]
            group-data-[status=incomplete]/stepper-step:group-not-[[data-status=current]+*]/stepper-step:transition-none
            rtl:flex-row-reverse
          `}
        >
          <span
            className={`
              flex-1 bg-(--border-color-brand-default) transition duration-300
              group-data-[status=complete]/stepper-step:bg-(--border-color-brand-subtle)
            `}
          />
          <span className="flex-1 bg-(--border-color-default)" />
        </span>
      </span>
    </li>
  )
}
StepperStep.displayName = 'Stepper.Step'
