import { forwardRef, memo } from "react";

import { styled } from "../../theme";

import { Flex } from "../flex";
import { ShowMoreButton } from "../show-more-button";
import { Text } from "../text";
import { useShowMoreText } from "./use-show-more-text";

const StyledText = styled(Text, {
  color: "$currentColor",
  overflow: "hidden",
  wordBreak: "break-word",
  textOverflow: "ellipsis",
  display: "-webkit-box",
  "-webkit-box-orient": "vertical",
});

const Container = styled(Flex, {
  color: "$off-white-72-opaque",
  flexDirection: "column",
  alignItems: "flex-start",
});

interface Props {
  /**
   * Full text to be shown
   */
  content: string;
  /**
   * Amount of rows to show in collapsed state
   */
  rowsToShow: number;
  /**
   * Text to show when button is collabsed
   */
  triggerCollapsedText: string;
  /**
   * Text to show when button is expanded
   */
  triggerExpandedText: string;
  /**
   * if `false` will hide the `ShowMoreButton`
   */
  showTrigger?: boolean;
  /**
   * The controlled expanded state.
   */
  isExpanded?: boolean;
  /**
   * Event handler called when the expanded state changes.
   */
  onExpandedChange?: (isExpanded: boolean) => void;
  /**
   * Customise text appearance
   */
  textProps?: Omit<React.ComponentProps<typeof Text>, "children">;
  /**
   * Customise the `ShowMoreButton`
   */
  triggerProps?: Omit<
    React.ComponentProps<typeof ShowMoreButton>,
    "expandedText" | "collapsedText" | "isExpanded" | "onExpandedChange"
  >;
}

// eslint-disable-next-line max-lines-per-function
const ShowMoreTextComponent = forwardRef<HTMLDivElement, Props>((props, ref) => {
  const {
    content,
    rowsToShow,
    triggerCollapsedText,
    triggerExpandedText,
    isExpanded: isExpandedProp,
    textProps,
    triggerProps,
    showTrigger = true,
    onExpandedChange,
  } = props;

  const {
    rows,
    textVariant,
    expectedHeightWhenClosed,
    isOverflow,
    textRef,
    isExpanded,
    handleOnExpandedChange,
    textId,
  } = useShowMoreText({
    rowsToShow,
    textVariantProps: textProps?.variant,
    trigger: content,
    isExpandedProp,
    onExpandedChange,
  });

  return (
    <Container ref={ref} data-state={isExpanded ? "open" : "closed"}>
      <StyledText
        {...textProps}
        id={textId}
        ref={textRef}
        variant={textVariant}
        css={{
          ...textProps?.css,
          ...(isOverflow && { "-webkit-line-clamp": rows }),
          ...(isExpanded
            ? { height: "auto", "-webkit-line-clamp": "unset" }
            : { maxHeight: expectedHeightWhenClosed }),
        }}
      >
        {content}
      </StyledText>
      {isOverflow && showTrigger && (
        <ShowMoreButton
          {...triggerProps}
          css={{ mt: "$1", ...triggerProps?.css }}
          expandedText={triggerExpandedText}
          collapsedText={triggerCollapsedText}
          aria-controls={textId}
          onExpandedChange={handleOnExpandedChange}
          {...(typeof isExpandedProp !== "undefined" && { isExpanded })}
        >
          {isExpanded ? triggerExpandedText : triggerCollapsedText}
        </ShowMoreButton>
      )}
    </Container>
  );
});

ShowMoreTextComponent.displayName = "ShowMoreText";

/**
 * A more specialised version of `ShowMoreButton` which allows for showing more and less of text.
 */
export const ShowMoreText = memo(ShowMoreTextComponent);
