import { h, type FunctionComponent } from 'preact'
import cn from 'classnames'

type Styles<C extends string, D extends string, S extends string> = {
  base?: string
  touched?: string
  element?: string
  label?: string
  icon?: string

  autoHeight?: string
  fullWidth?: string
  invert?: string
} & Record<C, string> &
  Record<D, string> &
  Record<S, string>

type Options<C extends string, D extends string, I extends string, S extends string> = {
  defaults: Pick<Props<C, D, I, S>, 'autoHeight' | 'color' | 'design' | 'fullWidth' | 'icon' | 'invert' | 'size'>
  icons: Record<I, string>
  styles: Styles<C, D, S>
}

type Props<C extends string, D extends string, I extends string, S extends string> = {
  autoHeight?: boolean
  className?: string
  color?: C
  design?: D
  href?: string
  fullWidth?: boolean
  icon?: I
  iconSize?: string
  invert?: boolean
  size?: S
  tabIndex?: number
  title?: string
}

export default function linkButtonFactory<
  C extends string = never,
  D extends string = never,
  I extends string = never,
  S extends string = never,
>({ defaults, icons, styles }: Options<C, D, I, S>) {
  const LinkButton: FunctionComponent<Props<C, D, I, S>> = ({
    autoHeight = defaults?.autoHeight,
    children,
    className,
    color = defaults?.color,
    design = defaults?.design,
    href,
    fullWidth = defaults?.fullWidth,
    icon = defaults?.icon,
    iconSize,
    invert = defaults?.invert,
    size = defaults?.size,
    tabIndex,
    title,
  }) => (
    <a
      className={cn(
        styles.base,
        design && styles[design],
        size && styles[size],
        color && styles[color],
        autoHeight && styles.autoHeight,
        fullWidth && styles.fullWidth,
        invert && styles.invert,
        className,
      )}
      style={iconSize && { '--icon-size': iconSize }}
      href={href}
      tabIndex={tabIndex}
      title={title}
    >
      {icon && <i className={styles.icon} style={{ maskImage: `url(${icons[icon] || icon})` }} />}
      {children && <span>{children}</span>}
    </a>
  )

  return LinkButton
}
