import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';
import './toast.css';

export type ToastVariant =
  | 'primary'
  | 'secondary'
  | 'success'
  | 'danger'
  | 'warning'
  | 'info'
  | 'light'
  | 'dark'
  // Back-compat alias
  | 'error';
export type ToastPosition =
  | 'top-start'
  | 'top-center'
  | 'top-end'
  | 'middle-start'
  | 'middle-center'
  | 'middle-end'
  | 'bottom-start'
  | 'bottom-center'
  | 'bottom-end'
  // Back-compat aliases
  | 'top-right'
  | 'top-left'
  | 'bottom-right'
  | 'bottom-left';
export type ToastAnimation = 'slide' | 'fade' | 'none';
export type ToastRole = 'alert' | 'status' | 'log';

export type ToastProps = {
  variant?: ToastVariant;
  message?: string;
  title?: string;
  duration?: number;
  dismissible?: boolean;
  position?: ToastPosition;
  animation?: ToastAnimation;
  showProgress?: boolean;
  pauseOnHover?: boolean;
  ariaLive?: 'polite' | 'assertive' | 'off';
  role?: ToastRole;
  onClose?: () => void;
};

function defaultIcon(variant: ToastVariant): string {
  switch (variant) {
    case 'primary':
      return '●';
    case 'secondary':
      return '●';
    case 'success':
      return '✓';
    case 'warning':
      return '⚠';
    case 'error':
      return '✕';
    case 'danger':
      return '✕';
    case 'light':
      return 'ℹ';
    case 'dark':
      return 'ℹ';
    case 'info':
    default:
      return 'ℹ';
  }
}

function normalizePosition(pos: ToastPosition): Exclude<
  ToastPosition,
  'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'
> {
  switch (pos) {
    case 'top-right':
      return 'top-end';
    case 'top-left':
      return 'top-start';
    case 'bottom-right':
      return 'bottom-end';
    case 'bottom-left':
      return 'bottom-start';
    default:
      return pos;
  }
}

export function Toast({
  variant = 'info',
  message = '',
  title,
  duration = 3000,
  dismissible = true,
  position = 'bottom-end',
  animation = 'slide',
  showProgress = true,
  pauseOnHover = true,
  ariaLive = 'polite',
  role = 'status',
  onClose,
}: ToastProps) {
  const toastId = useId().replace(/:/g, '');
  const [isVisible, setIsVisible] = useState(false);
  const [isExiting, setIsExiting] = useState(false);
  const [progress, setProgress] = useState(100);
  const timerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
  const progressRef = useRef<ReturnType<typeof setInterval> | undefined>(undefined);

  const clearTimers = useCallback(() => {
    if (timerRef.current) clearTimeout(timerRef.current);
    if (progressRef.current) clearInterval(progressRef.current);
  }, []);

  const close = useCallback(() => {
    setIsExiting(true);
    setIsVisible(false);
    clearTimers();
    window.setTimeout(() => onClose?.(), 300);
  }, [clearTimers, onClose]);

  const startTimers = useCallback(
    (remainingMs: number, startProgress: number) => {
      clearTimers();
      if (remainingMs <= 0) return;
      timerRef.current = setTimeout(() => close(), remainingMs);
      if (showProgress) {
        const interval = 50;
        const decrement = (interval / remainingMs) * 100;
        setProgress(startProgress);
        progressRef.current = setInterval(() => {
          setProgress((p) => {
            const next = p - decrement;
            if (next <= 0) {
              if (progressRef.current) clearInterval(progressRef.current);
              return 0;
            }
            return next;
          });
        }, interval);
      }
    },
    [clearTimers, close, showProgress]
  );

  useEffect(() => {
    const t = window.setTimeout(() => setIsVisible(true), 10);
    const t2 = window.setTimeout(() => {
      if (duration > 0) startTimers(duration, 100);
    }, 0);
    return () => {
      window.clearTimeout(t);
      window.clearTimeout(t2);
      clearTimers();
    };
    // Mount-only: enter animation + auto-dismiss timers (parity with Angular toast).
    // eslint-disable-next-line react-hooks/exhaustive-deps -- intentional single mount
  }, []);

  const onMouseEnter = useCallback(() => {
    if (!pauseOnHover || duration <= 0) return;
    clearTimers();
  }, [clearTimers, duration, pauseOnHover]);

  const onMouseLeave = useCallback(() => {
    if (!pauseOnHover || duration <= 0) return;
    const remaining = (progress / 100) * duration;
    startTimers(remaining, progress);
  }, [duration, pauseOnHover, progress, startTimers]);

  const normalizedPosition = useMemo(() => normalizePosition(position), [position]);

  return (
    <div
      id={toastId}
      className={`ccl-toast ccl-toast--${variant} ccl-toast--${normalizedPosition} ccl-toast--${animation}${
        isVisible ? ' ccl-toast--visible' : ''
      }${isExiting ? ' ccl-toast--exiting' : ''}`}
      role={role}
      aria-live={ariaLive}
      aria-labelledby={title ? `${toastId}-title` : undefined}
      onMouseEnter={onMouseEnter}
      onMouseLeave={onMouseLeave}
    >
      {title ? (
        <div className="ccl-toast__header">
          <span className="ccl-toast__icon" aria-hidden>
            {defaultIcon(variant)}
          </span>
          <strong id={`${toastId}-title`} className="ccl-toast__title">
            {title}
          </strong>
          {dismissible ? (
            <button type="button" className="ccl-toast__close" aria-label="Close notification" onClick={close}>
              <svg className="ccl-toast__close-icon" viewBox="0 0 16 16" aria-hidden focusable="false">
                <path
                  d="M2.146 2.146a.5.5 0 0 1 .708 0L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8 2.146 2.854a.5.5 0 0 1 0-.708z"
                  fill="currentColor"
                />
              </svg>
            </button>
          ) : null}
        </div>
      ) : dismissible ? (
        <button type="button" className="ccl-toast__close ccl-toast__close--floating" aria-label="Close notification" onClick={close}>
          <svg className="ccl-toast__close-icon" viewBox="0 0 16 16" aria-hidden focusable="false">
            <path
              d="M2.146 2.146a.5.5 0 0 1 .708 0L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8 2.146 2.854a.5.5 0 0 1 0-.708z"
              fill="currentColor"
            />
          </svg>
        </button>
      ) : null}

      <div className="ccl-toast__body">
        {!title ? (
          <span className="ccl-toast__icon ccl-toast__icon--inline" aria-hidden>
            {defaultIcon(variant)}
          </span>
        ) : null}
        <div className="ccl-toast__message">{message}</div>
      </div>

      {showProgress && duration > 0 ? (
        <div className="ccl-toast__progress" aria-hidden>
          <div className="ccl-toast__progress-bar" style={{ width: `${progress}%` }} />
        </div>
      ) : null}
    </div>
  );
}
