import * as React from 'react';
import clsx from 'clsx';

/**
 * Derived HTML element of the {@link KeyValueTable} component.
 */
export type KeyValueTableDerivedElement = HTMLDListElement;

/**
 * Individual property of the {@link KeyValueTable} component.
 */
export interface KeyValueTableProperty {
  /**
   * Key of the property.
   */
  key: string;
  /**
   * Class name of the property.
   */
  className?: string;
  /**
   * Value of the property.
   */
  valueProps?: React.HTMLProps<HTMLElement>;
}

/**
 * Props of the {@link KeyValueTable} component.
 */
export interface KeyValueTableProps extends Omit<React.HTMLProps<KeyValueTableDerivedElement>, 'children'> {
  /**
   * Should the keys be hidden?
   */
  hiddenKeys?: boolean;
  /**
   * Properties displayed on the component.
   */
  properties?: (KeyValueTableProperty | boolean | null | undefined)[];
}

/**
 * Component for displaying key-value pairs.
 */
export const KeyValueTable = React.forwardRef<KeyValueTableDerivedElement, KeyValueTableProps>((
  {
    hiddenKeys = false,
    properties = [],
    className,
    style,
    ...etcProps
  },
  forwardedRef,
) => (
  <dl
    {...etcProps}
    className={clsx(
      'grid gap-y-1 grid-cols-3',
      className,
    )}
    ref={forwardedRef}
    style={style}
  >
    {properties.map((property) => typeof property === 'object' && property && (
      <div
        key={property.key}
        className={clsx('contents', property.className)}
      >
        <dt
          className={clsx(hiddenKeys && 'sr-only', 'pr-4')}
        >
          {property.key}
        </dt>
        <dd
          {...(property.valueProps ?? {})}
          className={clsx(
            'm-0 text-ellipsis overflow-hidden',
            !hiddenKeys && 'col-span-2',
            hiddenKeys && 'col-span-3',
            property.valueProps?.className,
          )}
        >
          {property.valueProps?.children}
        </dd>
      </div>
    ))}
  </dl>
));

KeyValueTable.displayName = 'KeyValueTable';

KeyValueTable.defaultProps = {
  hiddenKeys: false,
  properties: [],
};
