import React, { useCallback, useRef, useState } from 'react';
import { createPortal } from 'react-dom';

import styles from './Controls.module.css';

export { Select, type SelectOption, type SelectProps } from './Select';

type ButtonProps = {
  children: React.ReactNode;
  onClick?: () => void;
  variant?: 'primary' | 'ghost';
  disabled?: boolean;
  title?: string | undefined;
  /** Подпись для скринридеров (иконки без текста). */
  ariaLabel?: string | undefined;
  /** Компактная кнопка под одну иконку. */
  iconOnly?: boolean;
  /** Позиция тултипа относительно кнопки. */
  tooltipPlacement?: 'top' | 'bottom' | 'bottom-left';
  'data-testid'?: string;
};

export function Button({
  children,
  onClick,
  variant = 'ghost',
  disabled = false,
  title,
  ariaLabel,
  iconOnly = false,
  tooltipPlacement = 'top',
  'data-testid': testId,
}: ButtonProps) {
  const btnRef = useRef<HTMLButtonElement | null>(null);
  const hostRef = useRef<HTMLSpanElement | null>(null);
  const [tipPos, setTipPos] = useState<{ x: number; y: number } | null>(null);

  const showTip = useCallback(() => {
    if (!title) return;
    const el = disabled ? hostRef.current : btnRef.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    if (tooltipPlacement === 'bottom-left') {
      setTipPos({ x: r.right, y: r.bottom });
      return;
    }
    if (tooltipPlacement === 'bottom') {
      setTipPos({ x: r.left + r.width / 2, y: r.bottom });
      return;
    }
    setTipPos({ x: r.left + r.width / 2, y: r.top });
  }, [disabled, title, tooltipPlacement]);

  const hideTip = useCallback(() => {
    setTipPos(null);
  }, []);

  const btnClass = [
    styles.button,
    variant === 'primary' ? styles.buttonPrimary : '',
    iconOnly ? styles.iconOnly : '',
  ]
    .filter(Boolean)
    .join(' ');

  const tipClass =
    tooltipPlacement === 'bottom-left'
      ? styles.tooltipBottomLeft
      : tooltipPlacement === 'bottom'
        ? styles.tooltipBottom
        : styles.tooltipTop;

  const tip =
    title && tipPos && typeof document !== 'undefined'
      ? createPortal(
          <div role="tooltip" className={tipClass} style={{ left: tipPos.x, top: tipPos.y }}>
            {title}
          </div>,
          document.body,
        )
      : null;

  const button = (
    <button
      ref={btnRef}
      type="button"
      className={btnClass}
      disabled={disabled}
      aria-label={ariaLabel}
      data-testid={testId}
      onClick={disabled ? undefined : onClick}
      onMouseEnter={disabled ? undefined : showTip}
      onMouseLeave={disabled ? undefined : hideTip}
      onFocus={showTip}
      onBlur={hideTip}
    >
      {children}
    </button>
  );

  // Disabled buttons don't receive mouse events — host span keeps tooltip usable.
  // Single DOM root (not Fragment) so flex/grid parents don't mis-place the button.
  if (disabled && title) {
    return (
      <span className={styles.buttonHost}>
        <span ref={hostRef} className={styles.disabledTipHost} onMouseEnter={showTip} onMouseLeave={hideTip}>
          {button}
        </span>
        {tip}
      </span>
    );
  }

  return (
    <span className={styles.buttonHost}>
      {button}
      {tip}
    </span>
  );
}

type InputProps = {
  value: string;
  placeholder?: string;
  onChange: (v: string) => void;
  autoFocus?: boolean;
  onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
  onBlur?: () => void;
};

export function Input({ value, placeholder, onChange, autoFocus, onKeyDown, onBlur }: InputProps) {
  return (
    <input
      className={styles.input}
      value={value}
      placeholder={placeholder}
      autoFocus={autoFocus}
      onChange={(e) => onChange(e.target.value)}
      onKeyDown={onKeyDown}
      onBlur={onBlur}
    />
  );
}
