import { IButtonSizes, type IButtonClassProps } from '@/Components/Buttons/Types'
import { twMerge } from 'tailwind-merge'
import { cva } from "class-variance-authority"
import { cn } from "@/lib/utils"

interface sizeProps {
  [key: string]: string
  xs: string
  sm: string
  med: string
  md: string
  lg: string
  xlg: string
}

const sizes: sizeProps = {
  xs: 'text-xs py-1 px-2',
  sm: 'text-sm py-2 px-3',
  med: 'text-base p-3',
  md: 'text-base p-3',
  lg: 'text-lg p-4',
  xlg: 'text-xl p-5'
}

const iconSizeProps: sizeProps = {
  xs: 'w-4 h-4',
  sm: 'w-6 h-6',
  med: 'w-10 h-10',
  md: 'w-10 h-10',
  lg: 'w-12 h-12',
  xlg: 'w-16 h-16'
}

export function getClassForSize(size: string = 'med'): string {
  if (sizes[size] !== undefined) {
    return sizes[size]
  }
  return sizes.med
}

export function getIconClassForSize(size: string = 'med'): string {
  if (iconSizeProps[size] !== undefined) {
    return iconSizeProps[size]
  }
  return iconSizeProps.med
}

interface makeClassNameProps {
  size?: string
  defaultClassName?: string
  className?: string
  error?: string
  errorClassName?: string
  disabled?: boolean
  extras?: Array<string | undefined>
}


export function makeClassName({
  size,
  defaultClassName,
  className,
  error,
  errorClassName,
  disabled,
  extras
}: makeClassNameProps): string {
  const cl: string = className !== undefined ? className : ''
  const defaultCl: string = defaultClassName !== undefined ? defaultClassName : ''
  const errorClass: string = errorClassName !== undefined ? errorClassName : 'border-2 border-rose-600  focus:border-rose-600 focus:ring-offset-0'
  const hasError: boolean = error !== undefined
  return twMerge(
    size !== undefined ? getClassForSize(size) : '',
    defaultCl,
    extras?.filter(e => e !== undefined).join(' '),
    cl,
    hasError ? errorClass : ''
  )
}

const destructiveVariant = "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90"
const linkVariant = "text-primary underline-offset-4 hover:underline"

export const buttonVariants = cva(
  "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer disabled:cursor-not-allowed",
  {
    variants: {
      variant: {
        default:
          "bg-primary-foreground text-primary shadow hover:bg-primary/90 hover:text-primary-foreground",
        destructive:
          destructiveVariant,
        outline:
          "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
        ghost: "hover:bg-accent hover:text-accent-foreground",
        link: linkVariant,
        primary: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
        secondary:
          "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
        create: "bg-create text-create-foreground shadow-sm hover:bg-create/80",
        submit: "bg-submit text-submit-foreground shadow-sm hover:bg-submit/80",
        alert: destructiveVariant,
        dark: "bg-dark text-dark-foreground shadow-sm hover:bg-dark/80",
        none: linkVariant
      },
      size: {
        default: "h-9 px-4 py-2",
        xs: 'h-6 rounded-md px-2 text-[.65rem]',
        sm: "h-8 rounded-md px-3 text-xs",
        lg: "h-10 rounded-md px-8",
        xlg: "h-14 px-10 rounded-md text-lg",
        icon: "h-9 w-9",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
)

const sizeMap: Record<string, IButtonSizes> = {
  xs: 'xs',
  sm: 'sm',
  med: 'default',
  default: 'default',
  lg: 'lg',
  xl: 'xlg',
  xlg: 'xlg',
  icon: 'icon'
}

export function createButtonClass({
  className,
  type,
  variant,
  size = 'med'
}: IButtonClassProps): string {

  const variantToUse = variant ?? type ?? 'outline'
  const sizeToUse = size !== undefined && size !== null ? sizeMap[size] ?? 'default' : 'default'

  return cn(buttonVariants({ variant: variantToUse, size: sizeToUse, className }))
}
