import React, {
  CSSProperties,
  HTMLAttributes,
  ReactElement,
  useMemo,
} from 'react';
import classNames from 'classnames';
import { st, classes } from './MaxLines.st.css.js';

export type BaseComponentProps = Pick<
  HTMLAttributes<Element>,
  'className' | 'style'
>;

export interface MaxLinesProps<P extends BaseComponentProps>
  extends BaseComponentProps {
  maxLines?: number;
  webkitLineClamp?: boolean;
  lineHeight?: number;
  wordBreak: CSSProperties['wordBreak'];
  textOverflow?: CSSProperties['textOverflow'];
  children:
    | ReactElement<P>
    | ((props: BaseComponentProps) => React.ReactElement<P>);
}

export function MaxLines<P extends BaseComponentProps>(
  props: MaxLinesProps<P>,
) {
  const {
    children,
    maxLines = 1,
    lineHeight,
    webkitLineClamp,
    textOverflow,
    wordBreak,
    ...rest
  } = props;

  const style = useMemo<CSSProperties>(
    () => ({
      ...(webkitLineClamp && { WebkitLineClamp: maxLines }),
      ...(textOverflow && { textOverflow }),
      ...(lineHeight && {
        lineHeight: `${lineHeight}px`,
        maxHeight: `${lineHeight * maxLines}px`,
      }),
      wordBreak,
      ...rest.style,
    }),
    [rest.style, maxLines, webkitLineClamp, lineHeight],
  );

  const className = st(
    classes.root,
    {
      clamp: webkitLineClamp,
    },
    rest.className,
  );

  let child;
  if (typeof children === 'function') {
    child = children({ className, style });
  } else {
    const { type: WrappedComponent, props: wrappedProps } = children;

    child = (
      <WrappedComponent
        {...rest}
        {...wrappedProps}
        className={classNames(className, wrappedProps.className)}
        style={{ ...style, ...wrappedProps.style }}
      />
    );
  }

  return child;
}
