import React, { CSSProperties, useMemo, useRef } from 'react';
import { useAdjustFontSizeToFit } from './fitText/textFit';

type FitTextProps = {
  text: string;
  fontSize?: number; // px; if omitted, uses computed style
  minimumFontScale?: number; // 0..1
  lines?: number; // max lines
  className?: string;
  style?: CSSProperties;
  as?: 'span' | 'div';
  /**
   * Insert zero-width soft breaks after these characters to prefer wrapping at them
   * when multi-line is enabled. Defaults to '/'. Ignored when lines === 1.
   */
  softBreakChars?: string | string[];
};

const FitText: React.FC<FitTextProps> = ({
  text,
  fontSize,
  minimumFontScale = 0.8,
  lines = 1,
  className,
  style,
  as = 'span',
  softBreakChars = '/',
}) => {
  const ref = useRef<HTMLElement | null>(null);

  // Hook runs after mount and on size/text changes; uses observers internally
  useAdjustFontSizeToFit(ref as any, {
    maxFontSizePx: fontSize,
    minFontScale: minimumFontScale,
    maxLines: lines,
    singleLine: lines === 1,
  });

  // Memoize the HTML tag to render (span/div) from the `as` prop so
  // React doesn't create a new component function on each render.
  const ElementTag: any = useMemo(() => as, [as]);

  // For the / character, insert zero-width soft breaks to prefer wrapping at them
  const displayText = useMemo(() => {
    if (!text) return text;
    if (!lines || lines <= 1) return text;
    const chars = Array.isArray(softBreakChars) ? softBreakChars : [softBreakChars];
    const esc = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    const re = new RegExp(`(${chars.filter(Boolean).map(esc).join('|')})`, 'g');
    return text.replace(re, `$1\u200B`);
  }, [text, lines, softBreakChars]);

  const clampStyles: CSSProperties = {
    // Multi-line clamp with ellipsis fallback
    whiteSpace: lines === 1 ? 'nowrap' : 'normal',
    overflow: 'hidden',
    textOverflow: 'ellipsis',
    display: lines > 1 ? ('-webkit-box' as any) : undefined,
    WebkitBoxOrient: lines > 1 ? ('vertical' as any) : undefined,
    WebkitLineClamp: lines > 1 ? (lines as any) : undefined,
    lineClamp: lines > 1 ? (lines as any) : undefined,
    // Favor shrinking over breaking words; only break at natural spaces or softBreakChars
    wordBreak: lines > 1 ? ('keep-all' as any) : ('normal' as any),
    overflowWrap: 'normal',
    fontSize: fontSize ? `${fontSize}px` : undefined,
  };

  return (
    <ElementTag ref={ref} className={className} style={{ ...clampStyles, ...style }}>
      {displayText}
    </ElementTag>
  );
};

export default FitText;


