import React, {
  createContext,
  useContext,
  useState,
  useMemo,
  PropsWithChildren,
} from 'react';
import {DefaultMessage} from '@modules/chats/interfaces';

// Context state interface
interface MessageActionsState {
  /**
   * The message that the user is interacting with.
   */
  targetMessage: Nullable<DefaultMessage>;
  /**
   * The action that the user is performing.
   */
  action: 'EDIT' | 'REPLY' | 'DELETE' | 'FORWARD' | 'NONE';
  /**
   * If true, the context is active and the user can interact with the menu.
   */
  isActive: boolean;
  /**
   * If true, the action menu is visible.
   */
  isActionMenuVisible: boolean;
  /**
   * If true, the reactions menu is visible.
   */
  isReactMenuVisible: boolean;
  /**
   * The top position of the menu.
   */
  menuTop: number;
  isReplying: boolean;
  isEditing: boolean;
  isDeleting: boolean;
  isForwarding: boolean;
  isPinFailedVisible: boolean;
}

// Context actions interface
interface MessageActionsActions {
  showFullMenu: (targetMessage: DefaultMessage, top: number) => void;
  showOnlyReactionsMenu: (targetMessage: DefaultMessage, top: number) => void;
  /**
   * Close action menu and reactions menu. But keep the action type and target message.
   */
  closeMenus: () => void;
  /**
   * Close action menu, reactions menu, and the blur. But keep the action type and target message.
   */
  closeAll: () => void;
  startEditing: () => void;
  startReplying: () => void;
  startDeleting: () => void;
  startForwarding: () => void;
  /**
   * Reset the context to the initial state.
   */
  reset: () => void;
  togglePinFailed: () => void;
}

// Combined context value
interface MessageActionsContextValue
  extends MessageActionsState,
    MessageActionsActions {}

// Create separate contexts for state and actions
const MessageActionsStateContext = createContext<
  MessageActionsState | undefined
>(undefined);
const MessageActionsActionsContext = createContext<
  MessageActionsActions | undefined
>(undefined);

const initialState: MessageActionsState = {
  targetMessage: null,
  action: 'NONE',
  isActive: false,
  isActionMenuVisible: false,
  isReactMenuVisible: false,
  menuTop: 0,
  isReplying: false,
  isEditing: false,
  isDeleting: false,
  isForwarding: false,
  isPinFailedVisible: false,
};

// Provider component
export const MessageActionsProvider: React.FC<PropsWithChildren> = ({
  children,
}) => {
  const [state, setState] = useState<MessageActionsState>(initialState);

  // Actions are stable and don't depend on state value
  const actions = useMemo((): MessageActionsActions => {
    return {
      showFullMenu: (targetMessage: DefaultMessage, top: number) => {
        setState(prev => ({
          ...prev,
          isActive: true,
          isActionMenuVisible: true,
          isReactMenuVisible: true,
          menuTop: top,
          targetMessage,
        }));
      },
      showOnlyReactionsMenu: (targetMessage: DefaultMessage, top: number) => {
        setState(prev => ({
          ...prev,
          isActive: true,
          isActionMenuVisible: false,
          isReactMenuVisible: true,
          menuTop: top,
          targetMessage,
        }));
      },
      startEditing: () => {
        setState(prev => ({...prev, action: 'EDIT'}));
      },
      startReplying: () => {
        setState(prev => ({...prev, action: 'REPLY'}));
      },
      startDeleting: () => {
        setState(prev => ({...prev, action: 'DELETE'}));
      },
      startForwarding: () => {
        setState(prev => ({...prev, action: 'FORWARD'}));
      },
      closeAll: () => {
        setState(prev => ({
          ...prev,
          isActive: false,
          isActionMenuVisible: false,
          isReactMenuVisible: false,
        }));
      },
      closeMenus: () => {
        setState(prev => ({
          ...prev,
          isActionMenuVisible: false,
          isReactMenuVisible: false,
        }));
      },
      reset: () => {
        setState(initialState);
      },
      togglePinFailed: () => {
        setState(prev => ({
          ...prev,
          isPinFailedVisible: !prev.isPinFailedVisible,
        }));
      },
    };
  }, []); // Empty dependency array - actions never change

  // Computed state values
  const stateValue = useMemo(
    (): MessageActionsState => ({
      ...state,
      isReplying: state.action === 'REPLY',
      isEditing: state.action === 'EDIT',
      isDeleting: state.action === 'DELETE',
      isForwarding: state.action === 'FORWARD',
    }),
    [state],
  );

  return (
    <MessageActionsActionsContext.Provider value={actions}>
      <MessageActionsStateContext.Provider value={stateValue}>
        {children}
      </MessageActionsStateContext.Provider>
    </MessageActionsActionsContext.Provider>
  );
};

/**
 * Hook to use only actions (no re-renders on state changes)
 */
export const useMessageActions = (): MessageActionsActions => {
  const context = useContext(MessageActionsActionsContext);

  if (context === undefined) {
    return {
      showFullMenu: () => {},
      showOnlyReactionsMenu: () => {},
      closeMenus: () => {},
      closeAll: () => {},
      startEditing: () => {},
      startReplying: () => {},
      startDeleting: () => {},
      startForwarding: () => {},
      reset: () => {},
      togglePinFailed: () => {},
    };
  }

  return context;
};

/**
 * Hook to use only state
 */
export const useMessageActionsState = (): MessageActionsState => {
  const context = useContext(MessageActionsStateContext);

  if (context === undefined) {
    return initialState;
  }

  return context;
};

/**
 * Hook to use both state and actions (for backward compatibility)
 */
export const useMessageActionsContext = (): MessageActionsContextValue => {
  const state = useMessageActionsState();
  const actions = useMessageActions();

  return {
    ...state,
    ...actions,
  };
};

/**
 * Hook to use only menu actions (optimized for components that only show menus)
 */
export const useShowMenu = () => {
  const actions = useMessageActions();

  return {
    showFullMenu: actions.showFullMenu,
    showOnlyReactionsMenu: actions.showOnlyReactionsMenu,
  };
};
