import {
  cloneElement,
  isValidElement,
  useId,
  type HTMLAttributes,
  type ReactElement,
  type ReactNode,
  type Ref,
} from 'react';
import './tooltip.css';

export type TooltipPlacement = 'top' | 'bottom' | 'left' | 'right';

export type TooltipProps = {
  /** Tooltip body (plain text or nodes). */
  content: ReactNode;
  children: ReactNode;
  placement?: TooltipPlacement;
  /** When true, children render unchanged and no tooltip is shown. */
  disabled?: boolean;
} & Omit<HTMLAttributes<HTMLSpanElement>, 'children'>;

function mergeDescribedBy(prev: string | undefined, next: string | undefined): string | undefined {
  if (!next) return prev;
  if (!prev) return next;
  return `${prev} ${next}`;
}

function mergeRefs<T>(...refs: Array<Ref<T> | undefined>): Ref<T> | undefined {
  const filtered = refs.filter((r) => r != null) as Array<Ref<T>>;
  if (filtered.length === 0) return undefined;
  return (node: T | null) => {
    filtered.forEach((ref) => {
      if (typeof ref === 'function') ref(node);
      else (ref as unknown as { current: T | null }).current = node;
    });
  };
}

export function Tooltip({ content, children, placement = 'top', className, disabled = false, ...rest }: TooltipProps) {
  const tipId = `ccl-tip-${useId().replace(/:/g, '')}`;
  const hide = disabled || content == null;

  if (hide) {
    return <>{children}</>;
  }

  const rootClass = ['ccl-tooltip', `ccl-tooltip--${placement}`, className ?? ''].filter(Boolean).join(' ');

  let trigger: ReactNode = children;
  if (isValidElement(children)) {
    const child = children as ReactElement<
      Record<string, unknown> & { ref?: Ref<HTMLElement>; 'aria-describedby'?: string }
    >;
    const prevDesc = typeof child.props['aria-describedby'] === 'string' ? child.props['aria-describedby'] : undefined;
    const childRef = (child as unknown as { ref?: Ref<HTMLElement> }).ref;
    trigger = cloneElement(child, {
      'aria-describedby': mergeDescribedBy(prevDesc, tipId),
      ref: mergeRefs(childRef),
    });
  } else {
    trigger = (
      <span className="ccl-tooltip__text-trigger" tabIndex={0} aria-describedby={tipId}>
        {children}
      </span>
    );
  }

  return (
    <span className={rootClass} {...rest}>
      {trigger}
      <span id={tipId} role="tooltip" className="ccl-tooltip__panel">
        {content}
      </span>
    </span>
  );
}
