import { useState, useRef, useMemo, useEffect } from 'react';

import DOMPurify from 'dompurify';
import { SxProps, Theme } from '@material-hu/mui/styles';
import Typography, { TypographyProps } from '@material-hu/mui/Typography';

import Button, {
  ButtonProps,
} from '@material-hu/components/design-system/Buttons/Button';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { mapNewLines, isTextClamped } from 'src/utils/text';

export type ShowMoreTextProps = TypographyProps & {
  more?: string;
  less?: string;
  lines?: number;
  isHtmlText?: boolean;
  text: string;
  buttonProps?: ButtonProps;
  onlyButtonText?: boolean;
};

const ShowMoreText = ({
  more,
  less,
  lines = 3,
  isHtmlText = false,
  text,
  buttonProps,
  onlyButtonText = false,
  ...typographyProps
}: ShowMoreTextProps) => {
  const [show, setShow] = useState<boolean>(false);
  const [isClamped, setIsClamped] = useState(false);
  const textRef = useRef<HTMLElement | null>(null);
  const { t } = useLokaliseTranslation();

  const handleSeeMore = (event: React.MouseEvent) => {
    event.stopPropagation();
    setShow(true);
  };

  const handleSeeLess = (event: React.MouseEvent) => {
    event.stopPropagation();
    setShow(false);
  };

  const formatedText = useMemo(() => mapNewLines(text), [text]);
  const sanitizedHtmlText = useMemo(
    () =>
      DOMPurify.sanitize(text, {
        USE_PROFILES: { html: true },
      }),
    [text],
  );

  const checkTextClamping = () => {
    if (!textRef.current) return;
    setIsClamped(isTextClamped(textRef));
  };

  useEffect(() => {
    checkTextClamping();

    window.addEventListener('resize', checkTextClamping);
    return () => {
      window.removeEventListener('resize', checkTextClamping);
    };
  }, [text, show]);

  const clampStyles: SxProps<Theme> = {
    width: '100%',
    display: '-webkit-box',
    overflow: 'hidden',
    WebkitBoxOrient: 'vertical',
    WebkitLineClamp: lines,
    WebkitBoxFlex: '1',
  };

  const expandedStyles: SxProps<Theme> = {
    width: '100%',
    display: 'block',
    overflow: 'visible',
  };

  const commonStyles: SxProps<Theme> = {
    wordWrap: 'break-word',
    overflowWrap: 'break-word',
    maxWidth: '100%',
    ...(show ? expandedStyles : clampStyles),
    ...typographyProps.sx,
  };

  const renderText = useMemo(() => {
    return isHtmlText ? (
      <Typography
        ref={textRef}
        {...typographyProps}
        sx={commonStyles}
        className={!show ? 'clamp' : 'expanded'}
        dangerouslySetInnerHTML={{ __html: sanitizedHtmlText }}
      />
    ) : (
      <Typography
        ref={textRef}
        {...typographyProps}
        sx={commonStyles}
        className={!show ? 'clamp' : 'expanded'}
      >
        {formatedText}
      </Typography>
    );
  }, [formatedText, isHtmlText, sanitizedHtmlText, show, typographyProps]);

  if (lines < 1 || !text) {
    return <Typography {...typographyProps}>{formatedText}</Typography>;
  }

  const buttonStyles = {
    ...buttonProps?.sx,
    ...(onlyButtonText && {
      maxWidth: 'fit-content',
      pl: 0,
      py: 0.5,
      justifyContent: 'start',
      '&:hover': {
        backgroundColor: 'transparent',
      },
    }),
  };

  return (
    <>
      {renderText}
      {show && (
        <Button
          {...buttonProps}
          component="span"
          sx={buttonStyles}
          onClick={handleSeeLess}
        >
          {less || t('SEE_LESS')}
        </Button>
      )}
      {!show && isClamped && (
        <Button
          {...buttonProps}
          component="span"
          sx={buttonStyles}
          onClick={handleSeeMore}
        >
          {more || t('SEE_MORE')}
        </Button>
      )}
    </>
  );
};

export default ShowMoreText;
