/* eslint-disable react/no-array-index-key */
import React, { useMemo } from "react"
import { AnimatePresence, motion } from "motion/react"
import { Block, useStyletron } from "@mezo-org/mezo-clay"

type SlotNumberProps = {
  className?: string
  children: number
  formatFunction?: (value: number) => string
}

type SlotNumberDigitProps = {
  className?: string
  children: number
}

function SlotNumberDigit(props: SlotNumberDigitProps) {
  const { children: value, ...restProps } = props

  const [css] = useStyletron()

  const digits = [...Array(10).keys()]

  return (
    <AnimatePresence initial={false}>
      <motion.div
        initial={{
          y: "100%",
        }}
        animate={{
          y: "0%",
        }}
        layout="position"
        className={css({
          position: "relative",
        })}
        {...restProps}
      >
        <Block
          overrides={{
            Block: {
              style: {
                visibility: "hidden",
              },
            },
          }}
        >
          {value}
        </Block>

        <motion.div
          className={css({
            display: "flex",
            flexDirection: "column",
            position: "absolute",
            inset: 0,
            height: "fit-content",
          })}
          initial={false}
          animate={{ y: `${(value / 10) * -100}%` }}
          transition={{
            type: "spring",
            damping: 16,
            stiffness: 220,
          }}
        >
          {digits.map((digit) => (
            <Block as="span" key={digit}>
              {digit}
            </Block>
          ))}
        </motion.div>
      </motion.div>
    </AnimatePresence>
  )
}

/**
 * SlotNumber component displays a number with animated digits.
 *
 * @typedef {object} SlotNumberProps
 * @property {number} children - The number to display.
 * @property {function} [formatFunction] - Optional function to format the number.
 * @property {BlockProps} [restProps] - Additional properties for the Block component.
 * @see https://pyszkowski.dev/writings/slot-number
 * @returns {JSX.Element} The rendered SlotNumber component.
 */
function SlotNumber(props: SlotNumberProps) {
  const { children: value, formatFunction, ...restProps } = props

  const [css] = useStyletron()

  const characters = useMemo(() => {
    const formattedValue = formatFunction
      ? formatFunction(value)
      : value.toString()

    return formattedValue
      .split("")
      .map((character) => (/^[0-9]$/.test(character) ? +character : character))
      .reverse()
  }, [formatFunction, value])

  return (
    <motion.div
      layout
      className={css({
        display: "inline-flex",
        flexDirection: "row-reverse",
        justifyContent: "flex-end",
        overflow: "hidden",
        userSelect: "none",
      })}
      {...restProps}
    >
      {characters.map((character, index) =>
        typeof character === "number" ? (
          <SlotNumberDigit key={`slot-number-character-${index}`}>
            {character}
          </SlotNumberDigit>
        ) : (
          <motion.span layout key={`slot-number-character-${index}`}>
            {character}
          </motion.span>
        ),
      )}
    </motion.div>
  )
}

export default SlotNumber
