'use client'

import type { ComponentProps } from 'react'

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

import { useCSSPropsPolyfill, useGDS } from '../hooks/index.ts'
import { cn, getCSSPropsAttributes, type Stringifiable } from '../utils/index.ts'
import { KeyboardMeta } from './Keyboard.meta.ts'

const SINGLE_KEY_CHARS = ['⌘', '⌥', '⇧', '^', '⏎', '⌫', '~', '␛', '/'] as const
const SINGLE_KEY_CHARS_REGEX = new RegExp(
  `(${SINGLE_KEY_CHARS.map((char) => char.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|')})`,
  'g',
)

export interface KeyboardProps
  extends ComponentProps<'kbd'>, GDSComponentProps<typeof KeyboardMeta> {
  children: Stringifiable
}

export function Keyboard({
  ref: passedRef,
  size,
  className,
  style,
  children,
  ...props
}: KeyboardProps) {
  useGDS()

  const [cssPropsPolyfillPassedRef, cssPropsPolyfillAttributes] = useCSSPropsPolyfill(
    KeyboardMeta,
    { size },
    { ref: passedRef },
  )

  const childrenArray = Array.isArray(children)
    ? children
    : typeof children === 'string'
      ? children
          .split(SINGLE_KEY_CHARS_REGEX)
          .map((part) => part.trim())
          .filter((part) => part.length > 0)
      : [children]

  return (
    <kbd
      ref={cssPropsPolyfillPassedRef}
      className={cn(
        `gds-keyboard root-inline u:shrink-0 u:font-mono u:whitespace-nowrap
        i:leading-0`,
        className,
      )}
      {...getCSSPropsAttributes(KeyboardMeta, { size }, style)}
      {...cssPropsPolyfillAttributes}
      {...props}
    >
      <span
        className={`
          inline-flex h-(--height) min-w-(--height) items-center justify-center rounded-4 border border-default
          @prop-size-small/keyboard:gap-0.5
          @prop-size-small/keyboard:px-0.75
          @prop-size-small/keyboard:text-10
          @prop-size-small/keyboard:[--height:--spacing(4)]
          @prop-size-medium/keyboard:gap-1
          @prop-size-medium/keyboard:px-1.25
          @prop-size-medium/keyboard:text-12
          @prop-size-medium/keyboard:[--height:--spacing(5)]
          @prop-size-large/keyboard:gap-1
          @prop-size-large/keyboard:px-1.25
          @prop-size-large/keyboard:text-14
          @prop-size-large/keyboard:[--height:--spacing(6)]
          ${/* Prevent incorrect alignment when empty */ ''}
          empty:after:content-nbsp
        `}
      >
        {childrenArray.map((child, index) => (
          <span key={index}>{child}</span>
        ))}
      </span>
    </kbd>
  )
}
