import { Slot } from '@radix-ui/react-slot'
import { type VariantProps } from 'class-variance-authority'
import type React from 'react'
import { cn } from '../../utils/cn'
import type { TypographyColor } from './foregroundColors'
import type { headingVariants, nonHeadingVariants } from './variants'
import { typographyVariants } from './variants'

type HeadingVariant = keyof typeof headingVariants
type NonHeadingVariant = keyof typeof nonHeadingVariants
type Variants = VariantProps<typeof typographyVariants>['variant']

type HeadingProps = React.HTMLAttributes<HTMLHeadingElement>
type ParagraphProps = React.HTMLAttributes<HTMLParagraphElement>
type SharedProps = {
  /**
   * Typography color uses semantic token names without the `-foreground` suffix.
   *
   * Example mappings:
   * - `color="progress"` -> `className="text-progress-foreground"`
   * - `color="link"` -> `className="text-link"`
   *
   * When translating from Figma or design token specs, use the base semantic token
   * name. For foreground tokens, drop the trailing `-foreground`.
   */
  color?: TypographyColor
  asChild?: boolean
  ref?: React.Ref<HTMLParagraphElement | HTMLHeadingElement>
}

type TypographyProps =
  | ({
      variant?: HeadingVariant
    } & SharedProps &
      HeadingProps)
  | ({
      variant?: NonHeadingVariant
    } & SharedProps &
      ParagraphProps)

function getTag(variant: Variants) {
  switch (variant) {
    case 'h1':
      return 'h1'
    case 'h2':
      return 'h2'
    case 'h3':
      return 'h3'
    case 'h4':
      return 'h4'
    case 'h5':
      return 'h5'
    case 'h6':
      return 'h6'
    default:
      return 'p'
  }
}

export const Typography = ({
  color,
  className,
  children,
  variant,
  asChild = false,
  ref,
  ...props
}: TypographyProps) => {
  const Tag = getTag(variant)
  const Component = asChild ? Slot : Tag

  return (
    <Component
      ref={ref}
      className={cn(typographyVariants({ variant, color }), className)}
      {...props}
    >
      {children}
    </Component>
  )
}

Typography.displayName = 'Typography'
