import PropTypes from "prop-types";
import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useRef,
  useState,
} from "react";

const DEFAULT_AUTO_HIDE_MS = 5000;

const MessageContext = createContext({
  isVisible: false,
  message: null,
  icon: null,
  showMessage: () => {},
  hideMessage: () => {},
});

export const MessageProvider = ({
  children,
  defaultAutoHideDelay = DEFAULT_AUTO_HIDE_MS,
}) => {
  const [state, setState] = useState({
    message: null,
    icon: null,
    isVisible: false,
  });

  const hideTimeoutRef = useRef(null);
  const clearHideTimeout = useCallback(() => {
    if (hideTimeoutRef.current) {
      window.clearTimeout(hideTimeoutRef.current);
      hideTimeoutRef.current = null;
    }
  }, []);

  const hideMessage = useCallback(() => {
    clearHideTimeout();
    setState((prev) => ({
      ...prev,
      isVisible: false,
    }));
  }, [clearHideTimeout]);

  const showMessage = useCallback(
    (messageText, icon = null, autoHide = true) => {
      if (!messageText) {
        console.warn("showMessage called without message text");
        return;
      }

      clearHideTimeout();

      setState({
        message: messageText,
        icon,
        isVisible: true,
      });

      const resolvedDelay =
        typeof autoHide === "number" && autoHide > 0
          ? autoHide
          : defaultAutoHideDelay;

      if (autoHide && typeof window !== "undefined") {
        hideTimeoutRef.current = window.setTimeout(() => {
          setState((prev) => ({
            ...prev,
            isVisible: false,
          }));
          hideTimeoutRef.current = null;
        }, resolvedDelay);
      }
    },
    [clearHideTimeout, defaultAutoHideDelay]
  );

  useEffect(() => {
    return () => {
      clearHideTimeout();
    };
  }, [clearHideTimeout]);

  const contextValue = useMemo(
    () => ({
      isVisible: state.isVisible,
      message: state.message,
      icon: state.icon,
      showMessage,
      hideMessage,
    }),
    [state.isVisible, state.message, state.icon, showMessage, hideMessage]
  );

  return (
    <MessageContext.Provider value={contextValue}>
      {children}
      <MessageOverlay
        message={state.message}
        icon={state.icon}
        isVisible={state.isVisible}
        onDismiss={hideMessage}
      />
    </MessageContext.Provider>
  );
};

MessageProvider.propTypes = {
  children: PropTypes.node.isRequired,
  defaultAutoHideDelay: PropTypes.number,
};

export const useMessage = () => useContext(MessageContext);

const MessageOverlay = ({ message, icon, isVisible, onDismiss }) => {
  const shouldRender = Boolean(message);

  if (!shouldRender) {
    return null;
  }

  const className = [
    "tb-message-popup",
    isVisible ? "tb-message-popup-visible" : "tb-message-popup-hidden",
  ]
    .filter(Boolean)
    .join(" ");

  return (
    <div
      className={className}
      role="status"
      aria-live="polite"
      aria-hidden={!isVisible}
    >
      <div className="tb-message-popup-content">
        {icon ? <span className="tb-message-popup-icon">{icon}</span> : null}
        <span className="tb-message-popup-text">{message}</span>
        <button
          type="button"
          className="tb-message-popup-dismiss"
          onClick={onDismiss}
          aria-label="Dismiss message"
        >
          {"\u00d7"}
        </button>
      </div>
    </div>
  );
};

MessageOverlay.propTypes = {
  message: PropTypes.string,
  icon: PropTypes.node,
  isVisible: PropTypes.bool.isRequired,
  onDismiss: PropTypes.func.isRequired,
};
