import clsx from 'clsx';
import { twMerge } from 'tailwind-merge';

import {
  PolymorphicComponent,
  PolymorphicComponentProps,
} from '@/utils/polymorphic';

export const skeletonBaseClasses = clsx(
  'relative block overflow-clip',
  // Primary and secondary colors
  'bg-(--skeleton-bg,var(--color-background-secondary))',
  'text-(--skeleton-fg,var(--color-opacity-white-4))',
  // Shimmer animation
  'before:absolute before:inset-0 before:animate-[shimmer_2s_infinite]',
  'before:bg-linear-to-r before:from-transparent before:via-current before:to-transparent'
);

/**
 * Yarrr, this component be a building block for skeleton loaders of all sorts!
 *
 * This defaults to being a `span` acting as a block-level element. BYO styling
 * to set the size, corner radius, or any other overrides.
 *
 * It shimmers like a treasure. The main and shimmer colors are controlled by
 * the background and text colors, respectively. You can override them directly
 * or set the `--skeleton-bg` and `--skeleton-fg` CSS variables, which is good
 * when you need to customize the color of a skeleton loader state composed of
 * multiple bones.
 */
export const SkeletonBone: PolymorphicComponent = <
  C extends React.ElementType = 'span',
>(
  props: PolymorphicComponentProps<C>
) => {
  const { as: Component = 'span', className, ...restProps } = props;
  return (
    <Component
      className={twMerge(skeletonBaseClasses, className)}
      {...restProps}
    />
  );
};

/**
 * Skeleton loader state that works well for text content
 *
 * The corners are rounded and the height and vertical margins correspond to
 * the current font size and line height
 */
export const SkeletonText: PolymorphicComponent = <
  C extends React.ElementType = 'span',
>(
  props: PolymorphicComponentProps<C>
) => {
  const { as: Component = 'span', className, ...restProps } = props;
  return (
    <Component
      className={twMerge(
        skeletonBaseClasses,
        'inline-block',
        'my-[calc(0.5*(1lh-1em))] h-[1em] rounded align-bottom',
        className
      )}
      {...restProps}
    />
  );
};
