import express from 'express';
import { join } from 'path';
import { logger } from '../logger.js';
import { loadConfig } from '../config.js';
import { ConfigManager } from '../config-manager.js';
import { mountConfigApi } from './config-api.js';
import {
  mountSetupApi,
  buildNoAuthConfigGate,
  newNoAuthConfigGateState,
  ensureSetupToken,
  clearSetupToken,
} from './setup-api.js';
import { resolveListenPort } from '../server/config.js';

/**
 * Browser setup wizard (fresh no-auth install onboarding) + Config API,
 * extracted verbatim from createCoreServer (bridge/server.ts).
 *
 * Token lifecycle + endpoints. The no-auth `/api/config` mutation gate
 * (Codex P1 #3) must register BEFORE mountConfigApi so it intercepts
 * PUT/POST while a setup window is open. See setup-api.ts.
 */
export function mountSetupAndConfigApis(
  app: express.Application,
  deps: {
    configManager: ConfigManager;
    authActive: boolean;
    listenPort?: number;
  },
): void {
  const { configManager, authActive, listenPort } = deps;

  const setupDataDir = join(process.cwd(), 'data');
  const setupListenPort =
    listenPort ?? resolveListenPort(process.env['PORT'], loadConfig().server?.port);
  // Synchronously seed the gate state to 'pending' (fail-closed for auth
  // writes) BEFORE the async lifecycle below resolves, so a request arriving
  // in the boot window can't slip an auth bootstrap through (Codex P1 #2).
  const setupGateState = newNoAuthConfigGateState();

  // Token lifecycle (needs the async setup-lib import). Created only on a
  // fresh no-auth install (needs-setup); cleared otherwise so existing
  // configured deployments keep their prior open behavior. On failure the
  // gate stays 'pending' (fail-closed), never silently open.
  void (async () => {
    try {
      if (authActive) {
        clearSetupToken(setupDataDir);
        return;
      }
      const { isLlmConfigured } = await import('../../scripts/setup-lib.mjs');
      const workers = configManager.getConfig().provider?.workers ?? [];
      if (!isLlmConfigured(workers)) {
        const token = ensureSetupToken(setupDataDir);
        setupGateState.mode = 'token-required';
        logger.info(`[setup] open the UI and enter this setup token: ${token}`);
        logger.info('[setup] llm configured=false → wizard active');
      } else {
        clearSetupToken(setupDataDir);
        setupGateState.mode = 'open';
        logger.info('[setup] llm configured=true → wizard off');
      }
    } catch (e) {
      logger.warn(`[setup] token lifecycle failed: ${String(e)}`);
    }
  })();

  // No-auth /api/config auth-write gate (only mounted in no-auth mode).
  if (!authActive) {
    app.use('/api/config', buildNoAuthConfigGate(setupDataDir, setupGateState));
  }

  mountSetupApi(app, configManager, {
    authActive,
    listenPort: setupListenPort,
    dataDir: setupDataDir,
  });

  mountConfigApi(app, configManager);
}
