"use client";

import classNames from "classnames/dedupe";
import type React from "react";
import type { RefAttributes } from "react";
import { useEffect, useId, useRef, useState } from "react";
import { useBreakpoint } from "../../hooks";
import type { DOMProps } from "../../types";
import { Accordion } from "../Accordion";
import { TextOrHTML } from "../TextOrHTML";
import type { AccordionProps } from "../Accordion/Accordion";
import type { TextProps } from "../Text/Text";
import "./ExpandableText.css";

export type ExpandableTextElementType = HTMLDivElement;

export interface ExpandableTextProps
  extends DOMProps, RefAttributes<ExpandableTextElementType> {
  /** The text content to display (can be plain text or HTML) */
  text: string;
  /** Maximum number of lines to show when collapsed */
  maxLines?: number;
  /** Breakpoint at which collapsing should be applied. If not provided, collapsing is always applied */
  breakpoint?: "xs" | "sm" | "md" | "lg" | "xl";
  /** Text for the expand trigger */
  showText?: string;
  /** Text for the collapse trigger */
  hideText?: string;
  /** Custom class name for the container */
  className?: string;
  /** Props to pass to the Text component */
  textProps?: Partial<TextProps>;
  /** Props to pass to the Accordion component */
  accordionProps?: Partial<AccordionProps>;
  /** Callback when expansion state changes */
  onToggle?: (expanded: boolean) => void;
}

export const ExpandableText = ({ ref, ...props }: ExpandableTextProps) => {
  const {
    text,
    maxLines = 3,
    breakpoint,
    showText = "Read more",
    hideText = "Read less",
    className,
    textProps = {},
    accordionProps = {},
    onToggle,
    ...otherProps
  } = props;

  const [isExpanded, setIsExpanded] = useState(false);
  const [isCollapsed, setIsCollapsed] = useState(false);
  const textRef = useRef<HTMLDivElement>(null);
  const { down } = useBreakpoint();

  // Generate unique ID for accessibility
  const baseId = useId();
  const expandButtonId = `expandable-text-expand-${baseId}`;

  // Determine if content should be collapsible based on breakpoint
  const shouldCollapse = breakpoint ? down(breakpoint) : true;

  useEffect(() => {
    if (!shouldCollapse || !textRef.current) {
      setIsCollapsed(false);
      return;
    }

    // Check if text is actually collapsed by comparing scroll height with client height
    const element = textRef.current;
    const isOverflowing = element.scrollHeight > element.clientHeight;
    setIsCollapsed(isOverflowing);
  }, [text, shouldCollapse, maxLines]);

  // If breakpoint is specified and we're above it, show full text without collapsible UI
  if (breakpoint && !shouldCollapse) {
    return (
      <div ref={ref} className={className} {...otherProps}>
        <TextOrHTML text={text} textWrapper {...textProps} />
      </div>
    );
  }

  const handleAccordionChange = (expanded: boolean) => {
    setIsExpanded(expanded);
    onToggle?.(expanded);
  };

  const classes = classNames("mobius-expandable-text", className);
  const textContainerClasses = classNames("mobius-expandable-text__content", {
    "mobius-expandable-text__content--collapsed": !isExpanded,
  });

  // CSS custom property for dynamic line clamping
  const textContainerStyle = {
    "--line-clamp": maxLines,
  } as React.CSSProperties;

  return (
    <div
      ref={ref}
      className={classes}
      data-testid="expandable-text"
      {...otherProps}
    >
      <div
        ref={textRef}
        className={textContainerClasses}
        style={textContainerStyle}
        data-testid="expandable-text-content"
        aria-describedby={isCollapsed ? expandButtonId : undefined}
      >
        <TextOrHTML elementType="span" textWrapper text={text} {...textProps} />
      </div>
      {isCollapsed && (
        <Accordion
          showText={showText}
          hideText={hideText}
          headerPosition="bottom"
          onChange={handleAccordionChange}
          onClick={(e?: React.MouseEvent) => {
            e?.stopPropagation();
          }}
          id={expandButtonId}
          {...accordionProps}
        />
      )}
    </div>
  );
};

ExpandableText.displayName = "ExpandableText";
