import { useKeyboard, useTerminalDimensions } from '@opentui/react';
import { useEffect, useRef, useState } from 'react';
import { sanitizeTerminalText } from '../../utils/terminal';
import { computeOverlayRect } from '../layout';
import { dispatchError, useAppDispatch, useAppState } from '../state/context';
import { terminalCellWidth, truncateTerminalText } from '../text';
import { colors } from '../theme';

export function ConfirmDialog() {
  const state = useAppState();
  const dispatch = useAppDispatch();
  const { width: terminalWidth, height: terminalHeight } = useTerminalDimensions();
  const action = state.confirmAction;
  const [pending, setPending] = useState(false);
  const [actionError, setActionError] = useState<string | null>(null);
  const pendingRef = useRef(false);
  const mountedRef = useRef(true);
  const operationRef = useRef(0);
  const layout = computeOverlayRect(terminalWidth, terminalHeight, {
    widthRatio: 0.5,
    minWidth: 24,
    height: 7,
    leftRatio: 0.25,
    topRatio: 0.4,
  });

  useEffect(() => {
    mountedRef.current = true;
    return () => {
      mountedRef.current = false;
      operationRef.current += 1;
    };
  }, []);

  useKeyboard((key) => {
    if (pendingRef.current) return;

    if (key.name === 'y' || key.name === 'enter' || key.name === 'return') {
      if (action) {
        pendingRef.current = true;
        setPending(true);
        setActionError(null);
        const operation = operationRef.current + 1;
        operationRef.current = operation;
        void Promise.resolve()
          .then(() => action.onConfirm())
          .then(() => {
            if (!mountedRef.current || operationRef.current !== operation) return;
            dispatch({ type: 'SET_CONFIRM', action: null });
          })
          .catch((err) => {
            if (!mountedRef.current || operationRef.current !== operation) return;
            pendingRef.current = false;
            setPending(false);
            const message = sanitizeTerminalText(err instanceof Error ? err.message : String(err));
            setActionError(message);
            dispatchError(dispatch, err);
          });
      }
      return;
    }

    if (key.name === 'n' || key.name === 'escape') {
      dispatch({ type: 'SET_CONFIRM', action: null });
      return;
    }
  });

  if (!action) return null;
  const message = sanitizeTerminalText(action.message);
  const options = 'y yes  n no';

  return (
    <box
      position="absolute"
      left={layout.left}
      top={layout.top}
      width={layout.width}
      height={layout.height}
      border
      borderStyle="rounded"
      borderColor={colors.accentYellow}
      title={truncateTerminalText(' Confirm ', Math.max(0, layout.width - 4))}
      titleAlignment="center"
      backgroundColor={colors.bg}
      padding={layout.padding}
      zIndex={100}
      flexDirection="column"
      alignItems="center"
    >
      {layout.contentHeight >= 1 ? (
        <text fg={colors.textPrimary}>{truncateTerminalText(message, layout.contentWidth)}</text>
      ) : null}
      {layout.contentHeight >= 3 && !actionError ? <box height={1} /> : null}
      {pending && layout.contentHeight >= 2 ? (
        <text fg={colors.accentYellow}>{truncateTerminalText('Working... input is locked', layout.contentWidth)}</text>
      ) : layout.contentHeight >= 2 && terminalCellWidth(options) <= layout.contentWidth ? (
        <text>
          <span fg={colors.accentGreen}>
            <strong>y</strong>
          </span>
          <span fg={colors.textSecondary}>{' yes  '}</span>
          <span fg={colors.accentRed}>
            <strong>n</strong>
          </span>
          <span fg={colors.textSecondary}>{' no'}</span>
        </text>
      ) : layout.contentHeight >= 2 ? (
        <text fg={colors.textSecondary}>{truncateTerminalText(options, layout.contentWidth)}</text>
      ) : null}
      {actionError && layout.contentHeight >= 3 ? (
        <text fg={colors.accentRed}>
          {truncateTerminalText(sanitizeTerminalText(actionError), layout.contentWidth)}
        </text>
      ) : null}
    </box>
  );
}
