import { useKeyboard, useTerminalDimensions } from '@opentui/react';
import { useEffect, useRef, useState } from 'react';
import { sanitizeTerminalText } from '../../utils/terminal';
import { getInstallCommand, markRemindLater, markVersionSkipped, runUpdateInstall } from '../../utils/update-check';
import { computeOverlayRect } from '../layout';
import { isTuiShutdownError, useTuiLifecycle } from '../lifecycle';
import { useAppDispatch, useAppState } from '../state/context';
import type { UpdateInfo } from '../state/types';
import { terminalCellWidth, truncateTerminalText } from '../text';
import { colors } from '../theme';

export interface UpdateOverlayProps {
  /** Injectable so installation behavior can be verified without spawning a process. */
  install?: (packageName: string, version: string, signal?: AbortSignal) => Promise<void>;
  /** Injectable cleanup/exit seam used after a successful install. */
  onInstallSuccess?: (info: UpdateInfo) => void;
}

async function installUpdate(packageName: string, version: string, signal?: AbortSignal): Promise<void> {
  await runUpdateInstall(packageName, version, undefined, signal);
}

export function UpdateOverlay({ install = installUpdate, onInstallSuccess }: UpdateOverlayProps = {}) {
  const state = useAppState();
  const dispatch = useAppDispatch();
  const lifecycle = useTuiLifecycle();
  const { width: terminalWidth, height: terminalHeight } = useTerminalDimensions();
  const info = state.updateInfo;
  const [installing, setInstalling] = useState(false);
  const [installError, setInstallError] = useState<string | null>(null);
  const mountedRef = useRef(true);
  const layout = computeOverlayRect(terminalWidth, terminalHeight, {
    widthRatio: 0.6,
    minWidth: 32,
    height: 12,
    leftRatio: 0.2,
    topRatio: 0.3,
  });

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

  const completeInstall = (installedInfo: UpdateInfo) => {
    if (onInstallSuccess) {
      onInstallSuccess(installedInfo);
      return;
    }
    void lifecycle.shutdown().then(
      () => {
        process.stdout.write(
          `\n✓ Installed ${sanitizeTerminalText(installedInfo.packageName)}@${sanitizeTerminalText(installedInfo.latestVersion)}. Re-run to use the new version.\n`,
        );
        process.exit(0);
      },
      (error: unknown) => {
        const message = error instanceof Error ? error.message : String(error);
        process.stderr.write(
          `\nUpdate installed, but rss-ai could not shut down cleanly: ${sanitizeTerminalText(message)}\n`,
        );
        process.exit(1);
      },
    );
  };

  useKeyboard((key) => {
    if (!info || installing) return;

    if (key.name === 'n' || key.name === 'enter' || key.name === 'return') {
      setInstalling(true);
      setInstallError(null);
      void lifecycle
        .run((signal) => install(info.packageName, info.latestVersion, signal))
        .then(() => completeInstall(info))
        .catch((err: unknown) => {
          if (isTuiShutdownError(err) || !mountedRef.current || !lifecycle.isAcceptingWork()) return;
          const message = err instanceof Error ? err.message : String(err);
          setInstallError(sanitizeTerminalText(message));
          setInstalling(false);
        });
      return;
    }

    if (key.name === 'l' || key.name === 'escape') {
      markRemindLater();
      dispatch({ type: 'SET_UPDATE_INFO', info: null });
      return;
    }

    if (key.name === 's') {
      markVersionSkipped(info.latestVersion);
      dispatch({ type: 'SET_UPDATE_INFO', info: null });
      return;
    }
  });

  if (!info) return null;
  const packageName = sanitizeTerminalText(info.packageName);
  const currentVersion = sanitizeTerminalText(info.currentVersion);
  const latestVersion = sanitizeTerminalText(info.latestVersion);
  const versionLine = `${packageName} ${currentVersion} → ${latestVersion}`;

  return (
    <box
      position="absolute"
      left={layout.left}
      top={layout.top}
      width={layout.width}
      height={layout.height}
      border
      borderStyle="rounded"
      borderColor={colors.accentGreen}
      title={truncateTerminalText(' Update Available ', Math.max(0, layout.width - 4))}
      titleAlignment="center"
      backgroundColor={colors.bg}
      padding={layout.padding}
      zIndex={100}
      flexDirection="column"
      alignItems="center"
    >
      {layout.contentHeight >= 1 ? (
        terminalCellWidth(versionLine) <= layout.contentWidth ? (
          <text>
            <span fg={colors.textPrimary}>{`${packageName} `}</span>
            <span fg={colors.textSecondary}>{currentVersion}</span>
            <span fg={colors.textMuted}>{' → '}</span>
            <span fg={colors.accentGreen}>
              <strong>{latestVersion}</strong>
            </span>
          </text>
        ) : (
          <text fg={colors.textPrimary}>{truncateTerminalText(versionLine, layout.contentWidth)}</text>
        )
      ) : null}

      {layout.contentHeight >= 4 ? <box height={1} /> : null}

      {installing ? (
        layout.contentHeight >= 2 ? (
          <text fg={colors.accentGreen}>{truncateTerminalText('Installing...', layout.contentWidth)}</text>
        ) : null
      ) : installError ? (
        <>
          {layout.contentHeight >= 2 ? (
            <text fg={colors.accentYellow}>
              {truncateTerminalText(`Update failed: ${sanitizeTerminalText(installError)}`, layout.contentWidth)}
            </text>
          ) : null}
          {layout.contentHeight >= 3 ? (
            <text fg={colors.textSecondary}>
              {truncateTerminalText('Press n to retry, l to try later, or s to skip.', layout.contentWidth)}
            </text>
          ) : null}
          {layout.contentHeight >= 4 ? (
            <text fg={colors.textMuted}>
              {truncateTerminalText(`Manual: ${getInstallCommand(packageName, latestVersion)}`, layout.contentWidth)}
            </text>
          ) : null}
        </>
      ) : (
        <>
          {layout.contentHeight >= 2 ? (
            terminalCellWidth('n update now   l later   s skip this version') <= layout.contentWidth ? (
              <text>
                <span fg={colors.accentGreen}>
                  <strong>n</strong>
                </span>
                <span fg={colors.textSecondary}>{' update now   '}</span>
                <span fg={colors.accentBlue}>
                  <strong>l</strong>
                </span>
                <span fg={colors.textSecondary}>{' later   '}</span>
                <span fg={colors.accentYellow}>
                  <strong>s</strong>
                </span>
                <span fg={colors.textSecondary}>{' skip this version'}</span>
              </text>
            ) : (
              <text fg={colors.textSecondary}>
                {truncateTerminalText('n update now   l later   s skip this version', layout.contentWidth)}
              </text>
            )
          ) : null}
          {layout.contentHeight >= 4 ? <box height={1} /> : null}
          {layout.contentHeight >= 3 ? (
            <text fg={colors.textMuted}>{truncateTerminalText('Esc to dismiss', layout.contentWidth)}</text>
          ) : null}
        </>
      )}
    </box>
  );
}
