import {
  useEffect,
  useRef,
  useState,
  type CSSProperties,
  type ReactNode,
} from 'react';

export interface ExplainThisProps {
  /** Slot whose selected text is the explanation target. */
  children: ReactNode;
  /**
   * Called when the user hits the "Explain" CTA. Receive the selected
   * text + a structured rect describing where the popover anchored
   * (useful for hosts that want to open a richer side-panel instead).
   */
  onExplain: (selection: { text: string; rect: DOMRect | null }) => void;
  /** Label on the floating button. Default "Explain". */
  ctaLabel?: string;
  /** Min characters required before the popover shows. Default 4. */
  minLength?: number;
  /** Bypass entirely. */
  disabled?: boolean;
  className?: string;
  style?: CSSProperties;
}

/**
 * `<ExplainThis>` — highlight any text inside the wrapped slot, a small
 * popover appears with an "Explain" CTA, the host calls the LLM with
 * the selected substring.
 *
 * Wave 9.E.3.
 *
 * Implementation: listens for `selectionchange` on the document while
 * mounted, only acts on selections wholly within our wrapper. Pops a
 * fixed-position button positioned at the centre of the selection
 * rect. Clears + hides itself when the selection collapses.
 */
export function ExplainThis({
  children,
  onExplain,
  ctaLabel = 'Explain',
  minLength = 4,
  disabled = false,
  className,
  style,
}: ExplainThisProps) {
  const wrapperRef = useRef<HTMLDivElement>(null);
  const [pop, setPop] = useState<{ x: number; y: number; text: string; rect: DOMRect } | null>(null);

  useEffect(() => {
    if (disabled) {
      setPop(null);
      return;
    }
    const onSelect = () => {
      const wrapper = wrapperRef.current;
      if (!wrapper) return;
      const sel = window.getSelection();
      if (!sel || sel.isCollapsed || sel.rangeCount === 0) {
        setPop(null);
        return;
      }
      const range = sel.getRangeAt(0);
      // Ignore selections that aren't fully inside our wrapper.
      if (!wrapper.contains(range.commonAncestorContainer)) {
        setPop(null);
        return;
      }
      const text = sel.toString().trim();
      if (text.length < minLength) {
        setPop(null);
        return;
      }
      const rect = range.getBoundingClientRect();
      setPop({
        text,
        rect,
        x: rect.left + rect.width / 2,
        y: rect.top - 8,
      });
    };
    document.addEventListener('selectionchange', onSelect);
    return () => document.removeEventListener('selectionchange', onSelect);
  }, [disabled, minLength]);

  const fire = () => {
    if (!pop) return;
    onExplain({ text: pop.text, rect: pop.rect });
    // Collapse selection so the popover disappears.
    window.getSelection()?.removeAllRanges();
    setPop(null);
  };

  return (
    <div
      ref={wrapperRef}
      data-testid="bl-explain-this"
      data-disabled={disabled ? 'true' : 'false'}
      className={className}
      style={style}
    >
      {children}
      {pop && (
        <button
          type="button"
          data-testid="bl-explain-this-popover"
          onMouseDown={(e) => e.preventDefault()}
          onClick={fire}
          style={{
            position: 'fixed',
            left: pop.x,
            top: pop.y,
            transform: 'translate(-50%, -100%)',
            zIndex: 50,
            padding: '4px 10px',
            borderRadius: 999,
            border: '1px solid var(--bl-accent, #6366f1)',
            background: 'var(--bl-accent, #6366f1)',
            color: 'var(--bl-on-accent, #fff)',
            fontSize: 12,
            fontWeight: 600,
            boxShadow: '0 8px 24px rgba(0,0,0,0.18)',
            cursor: 'pointer',
          }}
        >
          ✨ {ctaLabel}
        </button>
      )}
    </div>
  );
}
