// The console panel's command dispatch, factored out of ConsolePanel.jsx so
// the cross-boundary ctx shape and the changed→refresh fan-out are unit
// testable without rendering React.
import { runConsoleCommand } from '../platform';

/**
 * The ConsoleCtx the Rust `run_console_command` expects — camelCase, matching
 * the serde rename in TauriClient/src-tauri/src/shims.rs's `ConsoleCtx`. It
 * carries the GUI's live session plus its current project/workspace selection,
 * so the executor acts on exactly what the app is showing.
 */
export function buildConsoleCtx({ api, account, deviceId, activeProjectId, projectName, workspacePath }) {
  return {
    server: api.baseUrl,
    token: api.token,
    username: account?.username ?? '',
    deviceId,
    deviceName: account?.deviceName ?? '',
    projectId: activeProjectId ?? null,
    projectName: projectName ?? null,
    workspacePath: workspacePath || null,
  };
}

/**
 * Fan the executor's refresh hints out to the live data refreshers so the rest
 * of the app reflects what a command just changed: a checkout's lock, a
 * submit's new revision (files ⇒ tree + revisions), an adduser, or a
 * membership change.
 */
export function applyConsoleChanged(changed, refreshers) {
  for (const hint of changed ?? []) {
    if (hint === 'files') {
      refreshers.refreshDepotTree?.();
      refreshers.refreshRevisions?.();
    } else if (hint === 'locks') {
      refreshers.refreshLocks?.();
    } else if (hint === 'users') {
      refreshers.refreshUsers?.();
    } else if (hint === 'projects') {
      refreshers.refreshProjects?.();
    }
  }
}

/**
 * Build the ctx, run `command` through the shared executor, and — on success —
 * fan its `changed` hints out to the refreshers. `runner` is injectable so the
 * whole dispatch is testable against a mocked command runner.
 */
export async function dispatchConsole(command, conn, refreshers, runner = runConsoleCommand) {
  const ctx = buildConsoleCtx(conn);
  const result = await runner(command, ctx);
  if (result.ok) applyConsoleChanged(result.changed, refreshers);
  return { ctx, result };
}
