import { createCliRenderer } from '@opentui/core';
import { createRoot } from '@opentui/react';
import { closeDb, initDb } from '../db';
import { App } from './App';
import { createTuiLifecycle, registerTuiTerminationSignals } from './lifecycle';

/** Launch a fully initialized TUI, preserving the programmatic custom-database contract. */
export async function launchTui(dbPath?: string): Promise<void> {
  initDb(dbPath);
  let renderer: Awaited<ReturnType<typeof createCliRenderer>> | undefined;
  let removeTerminationListeners = () => {};
  let exitHandlerRegistered = false;
  let handleExit: (() => void) | undefined;
  try {
    renderer = await createCliRenderer({
      exitOnCtrlC: false,
      exitSignals: [],
    });
    const root = createRoot(renderer);
    handleExit = () => closeDb();
    const lifecycle = createTuiLifecycle({
      unmount: () => root.unmount(),
      destroyRenderer: () => {
        removeTerminationListeners();
        if (handleExit) process.off('exit', handleExit);
        renderer?.destroy();
      },
      closeDatabase: closeDb,
    });

    // Keep a process-exit fallback for consumers that launch the TUI directly,
    // but remove this per-session listener during normal lifecycle shutdown.
    process.once('exit', handleExit);
    exitHandlerRegistered = true;
    removeTerminationListeners = registerTuiTerminationSignals(lifecycle);

    root.render(<App lifecycle={lifecycle} />);
  } catch (error) {
    removeTerminationListeners();
    // A renderer/root construction failure occurs before the lifecycle can own
    // cleanup. Do not leave the database connection or signal listeners behind.
    if (exitHandlerRegistered && handleExit) process.off('exit', handleExit);
    try {
      renderer?.destroy();
    } catch {
      // Preserve the renderer/root construction error.
    }
    closeDb();
    throw error;
  }
}
