import { Command } from 'commander';
import http from 'node:http';
import https from 'node:https';

/** Pick the http or https driver based on the URL scheme. */
function httpDriverFor(url: string): typeof http | typeof https {
  return new URL(url).protocol === 'https:' ? https : http;
}
import { loadConfig } from '../config/index.js';
import type { ConfigLoaderDeps } from '../config/index.js';
import { loadCredentials } from '../auth/index.js';
import type { CredentialsDeps } from '../auth/index.js';
import { formatJson, formatYaml } from '../formatters/index.js';
import { APP_VERSION } from '@mcpctl/shared';

// ANSI helpers
const GREEN = '\x1b[32m';
const RED = '\x1b[31m';
const YELLOW = '\x1b[33m';
const DIM = '\x1b[2m';
const RESET = '\x1b[0m';
const CLEAR_LINE = '\x1b[2K\r';

interface ProviderDetail {
  managed: boolean;
  state?: string;
  lastError?: string;
}

interface ProvidersInfo {
  providers: string[];
  tiers: { fast: string[]; heavy: string[] };
  health: Record<string, boolean>;
  details?: Record<string, ProviderDetail>;
}

interface ServerLlm {
  id: string;
  name: string;
  type: string;
  model: string;
  tier: string;
  url: string;
  apiKeyRef?: { name: string; key: string } | null;
}

/**
 * SecretBackend row as returned by GET /api/v1/secretbackends, trimmed to the
 * fields the status view needs. `tokenMeta.lastRotationError` is mcpd's record
 * of the last credential-rotation failure (e.g. a dead OpenBao token).
 */
interface SecretBackendInfo {
  name: string;
  type: string;
  isDefault?: boolean;
  tokenMeta?: {
    lastRotationError?: string | null;
    lastRotationAt?: string | null;
    validUntil?: string | null;
  } | null;
}

/**
 * Result of a live "say hi" probe against a server LLM. `ok` says we got a
 * 200 + non-empty content back; `say` is the trimmed first 16 chars of the
 * reply for the user to spot-check (most LLMs say "hi", a misbehaving one
 * says "Hello! How can I assist…"). `ms` is end-to-end including TLS.
 */
export interface ServerLlmHealth {
  ok: boolean;
  ms: number;
  say?: string;
  error?: string;
}

export interface StatusCommandDeps {
  configDeps: Partial<ConfigLoaderDeps>;
  credentialsDeps: Partial<CredentialsDeps>;
  log: (...args: string[]) => void;
  write: (text: string) => void;
  checkHealth: (url: string) => Promise<boolean>;
  /** Check LLM health via mcplocal's /llm/health endpoint */
  checkLlm: (mcplocalUrl: string) => Promise<string>;
  /** Fetch available models from mcplocal's /llm/models endpoint */
  fetchModels: (mcplocalUrl: string) => Promise<string[]>;
  /** Fetch provider tier info from mcplocal's /llm/providers endpoint */
  fetchProviders: (mcplocalUrl: string) => Promise<ProvidersInfo | null>;
  /**
   * Fetch server-managed LLMs from mcpd (`mcpctl create llm` rows). Returns
   * null on auth failure, network error, or any other unhappy path so the
   * command stays printable even when mcpd is unreachable.
   */
  fetchServerLlms: (mcpdUrl: string, token: string | null) => Promise<ServerLlm[] | null>;
  /**
   * Probe a single server LLM with a tiny "say hi" prompt to check it's
   * actually serving inference. Used per-LLM in parallel after the fetch.
   * Always resolves (never throws) so one bad LLM doesn't sink the section.
   */
  probeServerLlm: (mcpdUrl: string, name: string, token: string | null) => Promise<ServerLlmHealth>;
  /** Fetch SecretBackends from mcpd to surface backend health. Null on error. */
  fetchSecretBackends: (mcpdUrl: string, token: string | null) => Promise<SecretBackendInfo[] | null>;
  isTTY: boolean;
}

function defaultCheckHealth(url: string): Promise<boolean> {
  return new Promise((resolve) => {
    let req: http.ClientRequest;
    try {
      req = httpDriverFor(url).get(`${url}/health`, { timeout: 3000 }, (res) => {
        resolve(res.statusCode !== undefined && res.statusCode >= 200 && res.statusCode < 400);
        res.resume();
      });
    } catch {
      resolve(false);
      return;
    }
    req.on('error', () => resolve(false));
    req.on('timeout', () => {
      req.destroy();
      resolve(false);
    });
  });
}

/**
 * Check LLM health by querying mcplocal's /llm/health endpoint.
 * This tests the actual provider running inside the daemon (uses persistent ACP for gemini, etc.)
 */
function defaultCheckLlm(mcplocalUrl: string): Promise<string> {
  return new Promise((resolve) => {
    let req: http.ClientRequest;
    try {
      req = httpDriverFor(mcplocalUrl).get(`${mcplocalUrl}/llm/health`, { timeout: 45000 }, (res) => {
        const chunks: Buffer[] = [];
        res.on('data', (chunk: Buffer) => chunks.push(chunk));
        res.on('end', () => {
          try {
            const body = JSON.parse(Buffer.concat(chunks).toString('utf-8')) as { status: string; error?: string };
            if (body.status === 'ok') {
              resolve('ok');
            } else if (body.status === 'not configured') {
              resolve('not configured');
            } else if (body.error) {
              resolve(body.error.slice(0, 80));
            } else {
              resolve(body.status);
            }
          } catch {
            resolve('invalid response');
          }
        });
      });
    } catch {
      resolve('mcplocal unreachable');
      return;
    }
    req.on('error', () => resolve('mcplocal unreachable'));
    req.on('timeout', () => { req.destroy(); resolve('timeout'); });
  });
}

function defaultFetchModels(mcplocalUrl: string): Promise<string[]> {
  return new Promise((resolve) => {
    let req: http.ClientRequest;
    try {
      req = httpDriverFor(mcplocalUrl).get(`${mcplocalUrl}/llm/models`, { timeout: 5000 }, (res) => {
        const chunks: Buffer[] = [];
        res.on('data', (chunk: Buffer) => chunks.push(chunk));
        res.on('end', () => {
          try {
            const body = JSON.parse(Buffer.concat(chunks).toString('utf-8')) as { models?: string[] };
            resolve(body.models ?? []);
          } catch {
            resolve([]);
          }
        });
      });
    } catch {
      resolve([]);
      return;
    }
    req.on('error', () => resolve([]));
    req.on('timeout', () => { req.destroy(); resolve([]); });
  });
}

function defaultFetchProviders(mcplocalUrl: string): Promise<ProvidersInfo | null> {
  return new Promise((resolve) => {
    let req: http.ClientRequest;
    try {
      req = httpDriverFor(mcplocalUrl).get(`${mcplocalUrl}/llm/providers`, { timeout: 5000 }, (res) => {
        const chunks: Buffer[] = [];
        res.on('data', (chunk: Buffer) => chunks.push(chunk));
        res.on('end', () => {
          try {
            const body = JSON.parse(Buffer.concat(chunks).toString('utf-8')) as ProvidersInfo;
            resolve(body);
          } catch {
            resolve(null);
          }
        });
      });
    } catch {
      resolve(null);
      return;
    }
    req.on('error', () => resolve(null));
    req.on('timeout', () => { req.destroy(); resolve(null); });
  });
}

/**
 * Fetch server-managed LLMs (the rows created by `mcpctl create llm`).
 * Goes directly to mcpd because mcplocal does not proxy /api/v1/llms.
 * Returns null on any error so the caller can decide whether to render
 * a "not available" line vs. spilling stack traces into the status view.
 */
function defaultFetchServerLlms(mcpdUrl: string, token: string | null): Promise<ServerLlm[] | null> {
  return new Promise((resolve) => {
    let req: http.ClientRequest;
    const headers: Record<string, string> = { Accept: 'application/json' };
    if (token !== null) headers['Authorization'] = `Bearer ${token}`;
    try {
      req = httpDriverFor(mcpdUrl).get(`${mcpdUrl}/api/v1/llms`, { timeout: 5000, headers }, (res) => {
        if (res.statusCode !== 200) { resolve(null); res.resume(); return; }
        const chunks: Buffer[] = [];
        res.on('data', (chunk: Buffer) => chunks.push(chunk));
        res.on('end', () => {
          try {
            resolve(JSON.parse(Buffer.concat(chunks).toString('utf-8')) as ServerLlm[]);
          } catch {
            resolve(null);
          }
        });
      });
    } catch {
      resolve(null);
      return;
    }
    req.on('error', () => resolve(null));
    req.on('timeout', () => { req.destroy(); resolve(null); });
  });
}

/**
 * Fetch SecretBackends from mcpd to surface backend health (e.g. an OpenBao
 * token that has gone dead). `tokenMeta.lastRotationError` is mcpd's own
 * record of the last rotation failure. Returns null on any error so the
 * section is simply omitted when mcpd is unreachable / unauthorized.
 */
function defaultFetchSecretBackends(mcpdUrl: string, token: string | null): Promise<SecretBackendInfo[] | null> {
  return new Promise((resolve) => {
    let req: http.ClientRequest;
    const headers: Record<string, string> = { Accept: 'application/json' };
    if (token !== null) headers['Authorization'] = `Bearer ${token}`;
    try {
      req = httpDriverFor(mcpdUrl).get(`${mcpdUrl}/api/v1/secretbackends`, { timeout: 5000, headers }, (res) => {
        if (res.statusCode !== 200) { resolve(null); res.resume(); return; }
        const chunks: Buffer[] = [];
        res.on('data', (chunk: Buffer) => chunks.push(chunk));
        res.on('end', () => {
          try {
            resolve(JSON.parse(Buffer.concat(chunks).toString('utf-8')) as SecretBackendInfo[]);
          } catch {
            resolve(null);
          }
        });
      });
    } catch {
      resolve(null);
      return;
    }
    req.on('error', () => resolve(null));
    req.on('timeout', () => { req.destroy(); resolve(null); });
  });
}

/**
 * POST a tiny "say hi" prompt to /api/v1/llms/<name>/infer and decide if
 * the LLM actually serves inference. Returns ok=true when the response is
 * 200 with non-empty content OR reasoning_content (thinking models often
 * spend their token budget on the reasoning trace and never emit a
 * `content` block, but they're clearly alive if reasoning came back).
 * Otherwise ok=false with an error string suitable for one-line display.
 *
 * `max_tokens: 64` gives reasoning models enough headroom to emit
 * something visible while still capping latency at ~1-2 sec on cheap
 * models. The exact wording — "Reply with just: hi" — is more terse and
 * closer to what a thinking model can short-circuit on without burning
 * its entire budget on reasoning.
 */
const PROBE_TIMEOUT_MS = 15_000;
const PROBE_BODY = JSON.stringify({
  messages: [{ role: 'user', content: 'Reply with just: hi' }],
  max_tokens: 64,
  temperature: 0,
});

function defaultProbeServerLlm(mcpdUrl: string, name: string, token: string | null): Promise<ServerLlmHealth> {
  return new Promise((resolve) => {
    const started = Date.now();
    const u = new URL(`${mcpdUrl}/api/v1/llms/${encodeURIComponent(name)}/infer`);
    const driver = u.protocol === 'https:' ? https : http;
    const headers: Record<string, string> = {
      'Content-Type': 'application/json',
      Accept: 'application/json',
      'Content-Length': String(Buffer.byteLength(PROBE_BODY)),
    };
    if (token !== null) headers['Authorization'] = `Bearer ${token}`;

    let req: http.ClientRequest;
    try {
      req = driver.request({
        hostname: u.hostname,
        port: u.port || (u.protocol === 'https:' ? 443 : 80),
        path: u.pathname + u.search,
        method: 'POST',
        headers,
        timeout: PROBE_TIMEOUT_MS,
      }, (res) => {
        const chunks: Buffer[] = [];
        res.on('data', (c: Buffer) => chunks.push(c));
        res.on('end', () => {
          const ms = Date.now() - started;
          const body = Buffer.concat(chunks).toString('utf-8');
          if ((res.statusCode ?? 0) !== 200) {
            // Pull out just the error message if the body is JSON, else the
            // raw status — keeps the line tidy.
            let msg = `HTTP ${String(res.statusCode ?? 0)}`;
            try {
              const parsed = JSON.parse(body) as { error?: string };
              if (typeof parsed.error === 'string') msg = parsed.error;
            } catch { /* not JSON, fall through */ }
            resolve({ ok: false, ms, error: msg.slice(0, 80) });
            return;
          }
          let content = '';
          let reasoning = '';
          try {
            const parsed = JSON.parse(body) as {
              choices?: Array<{ message?: { content?: string; reasoning_content?: string } }>;
            };
            const msg = parsed.choices?.[0]?.message;
            content = msg?.content?.trim() ?? '';
            reasoning = msg?.reasoning_content?.trim() ?? '';
          } catch {
            resolve({ ok: false, ms, error: 'invalid response body' });
            return;
          }
          if (content !== '') {
            resolve({ ok: true, ms, say: content.slice(0, 16) });
            return;
          }
          if (reasoning !== '') {
            // Thinking model burned its budget on the reasoning trace
            // before emitting `content`. The LLM is alive — flag it as
            // ok and surface a short reasoning preview so the user can
            // tell at a glance.
            resolve({ ok: true, ms, say: `[thinking] ${reasoning.slice(0, 12)}` });
            return;
          }
          resolve({ ok: false, ms, error: 'empty content' });
        });
      });
    } catch {
      resolve({ ok: false, ms: Date.now() - started, error: 'request failed' });
      return;
    }
    req.on('error', (e) => resolve({ ok: false, ms: Date.now() - started, error: e.message.slice(0, 80) }));
    req.on('timeout', () => { req.destroy(); resolve({ ok: false, ms: Date.now() - started, error: 'timeout' }); });
    req.write(PROBE_BODY);
    req.end();
  });
}

const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];

const defaultDeps: StatusCommandDeps = {
  configDeps: {},
  credentialsDeps: {},
  log: (...args) => console.log(...args),
  write: (text) => process.stdout.write(text),
  checkHealth: defaultCheckHealth,
  checkLlm: defaultCheckLlm,
  fetchModels: defaultFetchModels,
  fetchProviders: defaultFetchProviders,
  fetchServerLlms: defaultFetchServerLlms,
  fetchSecretBackends: defaultFetchSecretBackends,
  probeServerLlm: defaultProbeServerLlm,
  isTTY: process.stdout.isTTY ?? false,
};

/** Determine LLM label from config (handles both legacy and multi-provider formats). */
function getLlmLabel(llm: unknown): string | null {
  if (!llm || typeof llm !== 'object') return null;
  // Legacy format: { provider, model }
  if ('provider' in llm) {
    const legacy = llm as { provider: string; model?: string };
    if (legacy.provider === 'none') return null;
    return `${legacy.provider}${legacy.model ? ` / ${legacy.model}` : ''}`;
  }
  // Multi-provider format: { providers: [...] }
  if ('providers' in llm) {
    const multi = llm as { providers: Array<{ name: string; type: string; tier?: string }> };
    if (multi.providers.length === 0) return null;
    return multi.providers.map((p) => `${p.name}${p.tier ? ` (${p.tier})` : ''}`).join(', ');
  }
  return null;
}

/** Check if config uses multi-provider format. */
function isMultiProvider(llm: unknown): boolean {
  return !!llm && typeof llm === 'object' && 'providers' in llm;
}

/**
 * Format a single provider's status string for display.
 * Managed providers show lifecycle state; regular providers show health check result.
 */
function formatProviderStatus(name: string, info: ProvidersInfo, ansi: boolean): string {
  const detail = info.details?.[name];
  if (detail?.managed) {
    switch (detail.state) {
      case 'running':
        return ansi ? `${name} ${GREEN}✓ running${RESET}` : `${name} ✓ running`;
      case 'stopped':
        return ansi
          ? `${name} ${DIM}○ stopped (auto-starts on demand)${RESET}`
          : `${name} ○ stopped (auto-starts on demand)`;
      case 'starting':
        return ansi ? `${name} ${YELLOW}⟳ starting...${RESET}` : `${name} ⟳ starting...`;
      case 'error':
        return ansi
          ? `${name} ${RED}✗ error: ${detail.lastError ?? 'unknown'}${RESET}`
          : `${name} ✗ error: ${detail.lastError ?? 'unknown'}`;
      default: {
        const ok = info.health[name];
        return ansi
          ? ok ? `${name} ${GREEN}✓${RESET}` : `${name} ${RED}✗${RESET}`
          : ok ? `${name} ✓` : `${name} ✗`;
      }
    }
  }
  const ok = info.health[name];
  return ansi
    ? ok ? `${name} ${GREEN}✓${RESET}` : `${name} ${RED}✗${RESET}`
    : ok ? `${name} ✓` : `${name} ✗`;
}

export function createStatusCommand(deps?: Partial<StatusCommandDeps>): Command {
  const { configDeps, credentialsDeps, log, write, checkHealth, checkLlm, fetchModels, fetchProviders, fetchServerLlms, probeServerLlm, fetchSecretBackends, isTTY } = { ...defaultDeps, ...deps };

  return new Command('status')
    .description('Show mcpctl status and connectivity')
    .option('-o, --output <format>', 'output format (table, json, yaml)', 'table')
    .action(async (opts: { output: string }) => {
      const config = loadConfig(configDeps);
      const creds = loadCredentials(credentialsDeps);

      const llmLabel = getLlmLabel(config.llm);
      const multiProvider = isMultiProvider(config.llm);

      if (opts.output !== 'table') {
        // JSON/YAML: run everything in parallel, wait, output at once
        const token = creds?.token ?? null;
        const [mcplocalReachable, mcpdReachable, llmStatus, providersInfo, serverLlms, secretBackends] = await Promise.all([
          checkHealth(config.mcplocalUrl),
          checkHealth(config.mcpdUrl),
          llmLabel ? checkLlm(config.mcplocalUrl) : Promise.resolve(null),
          multiProvider ? fetchProviders(config.mcplocalUrl) : Promise.resolve(null),
          fetchServerLlms(config.mcpdUrl, token),
          fetchSecretBackends(config.mcpdUrl, token),
        ]);

        // Probe each server LLM in parallel — adds 0-2 sec to JSON mode but
        // gives consumers (scripts, dashboards) the same liveness signal as
        // the table view.
        const serverLlmsWithHealth = serverLlms !== null
          ? await Promise.all(serverLlms.map(async (l) => ({
              ...l,
              health: await probeServerLlm(config.mcpdUrl, l.name, token),
            })))
          : null;

        const llm = llmLabel
          ? llmStatus === 'ok' ? llmLabel : `${llmLabel} (${llmStatus})`
          : null;

        const status = {
          version: APP_VERSION,
          mcplocalUrl: config.mcplocalUrl,
          mcplocalReachable,
          mcpdUrl: config.mcpdUrl,
          mcpdReachable,
          auth: creds ? { user: creds.user } : null,
          registries: config.registries,
          outputFormat: config.outputFormat,
          llm,
          llmStatus,
          ...(providersInfo ? { providers: providersInfo } : {}),
          ...(serverLlmsWithHealth !== null ? { serverLlms: serverLlmsWithHealth } : {}),
          ...(secretBackends !== null ? { secretBackends: secretBackends.map((b) => ({ name: b.name, type: b.type, healthy: !b.tokenMeta?.lastRotationError, error: b.tokenMeta?.lastRotationError ?? null })) } : {}),
        };

        log(opts.output === 'json' ? formatJson(status) : formatYaml(status));
        return;
      }

      // Table format: print lines progressively, LLM last with spinner

      // Fast health checks first
      const [mcplocalReachable, mcpdReachable] = await Promise.all([
        checkHealth(config.mcplocalUrl),
        checkHealth(config.mcpdUrl),
      ]);

      log(`mcpctl v${APP_VERSION}`);
      log(`mcplocal:   ${config.mcplocalUrl} (${mcplocalReachable ? 'connected' : 'unreachable'})`);
      log(`mcpd:       ${config.mcpdUrl} (${mcpdReachable ? 'connected' : 'unreachable'})`);
      log(`Auth:       ${creds ? `logged in as ${creds.user}` : 'not logged in'}`);
      log(`Registries: ${config.registries.join(', ')}`);
      log(`Output:     ${config.outputFormat}`);

      // Server LLMs (mcpd-managed) — fetched in parallel regardless of the
      // local-LLM config, so the section renders even on machines without
      // a configured client-side provider.
      const token = creds?.token ?? null;
      const serverLlmsPromise = fetchServerLlms(config.mcpdUrl, token);
      const secretBackendsPromise = fetchSecretBackends(config.mcpdUrl, token);

      if (!llmLabel) {
        log(`LLM:        not configured (run 'mcpctl config setup')`);
        await renderSecretBackendsSection(secretBackendsPromise, isTTY);
        await renderServerLlmsSection(serverLlmsPromise, config.mcpdUrl, token, isTTY);
        return;
      }

      // LLM check + models + providers fetch in parallel
      const llmPromise = checkLlm(config.mcplocalUrl);
      const modelsPromise = fetchModels(config.mcplocalUrl);
      const providersPromise = multiProvider ? fetchProviders(config.mcplocalUrl) : Promise.resolve(null);

      if (isTTY) {
        let frame = 0;
        const interval = setInterval(() => {
          write(`${CLEAR_LINE}LLM:        ${DIM}${SPINNER_FRAMES[frame % SPINNER_FRAMES.length]} checking...${RESET}`);
          frame++;
        }, 80);

        const [llmStatus, models, providersInfo] = await Promise.all([llmPromise, modelsPromise, providersPromise]);
        clearInterval(interval);

        if (providersInfo && (providersInfo.tiers.fast.length > 0 || providersInfo.tiers.heavy.length > 0)) {
          // Tiered display with per-provider health
          write(`${CLEAR_LINE}`);
          for (const tier of ['fast', 'heavy'] as const) {
            const names = providersInfo.tiers[tier];
            if (names.length === 0) continue;
            const label = tier === 'fast' ? 'LLM (fast): ' : 'LLM (heavy):';
            const parts = names.map((n) => formatProviderStatus(n, providersInfo, true));
            log(`${label} ${parts.join(', ')}`);
          }
        } else {
          // Legacy single provider display
          if (llmStatus === 'ok' || llmStatus === 'ok (key stored)') {
            write(`${CLEAR_LINE}LLM:        ${llmLabel} ${GREEN}✓ ${llmStatus}${RESET}\n`);
          } else {
            write(`${CLEAR_LINE}LLM:        ${llmLabel} ${RED}✗ ${llmStatus}${RESET}\n`);
          }
        }
        if (models.length > 0) {
          log(`${DIM}            Available: ${models.join(', ')}${RESET}`);
        }
      } else {
        // Non-TTY: no spinner, just wait and print
        const [llmStatus, models, providersInfo] = await Promise.all([llmPromise, modelsPromise, providersPromise]);

        if (providersInfo && (providersInfo.tiers.fast.length > 0 || providersInfo.tiers.heavy.length > 0)) {
          for (const tier of ['fast', 'heavy'] as const) {
            const names = providersInfo.tiers[tier];
            if (names.length === 0) continue;
            const label = tier === 'fast' ? 'LLM (fast): ' : 'LLM (heavy):';
            const parts = names.map((n) => formatProviderStatus(n, providersInfo, false));
            log(`${label} ${parts.join(', ')}`);
          }
        } else {
          if (llmStatus === 'ok' || llmStatus === 'ok (key stored)') {
            log(`LLM:        ${llmLabel} ✓ ${llmStatus}`);
          } else {
            log(`LLM:        ${llmLabel} ✗ ${llmStatus}`);
          }
        }
        if (models.length > 0) {
          log(`${DIM}            Available: ${models.join(', ')}${RESET}`);
        }
      }

      await renderSecretBackendsSection(secretBackendsPromise, isTTY);
      await renderServerLlmsSection(serverLlmsPromise, config.mcpdUrl, token, isTTY);
    });

  /**
   * Print a "Secrets:" section listing each SecretBackend with health. A
   * backend with a `tokenMeta.lastRotationError` (e.g. a dead OpenBao token)
   * renders red with the error inline, so a recurrence is visible at a glance
   * from `mcpctl status` instead of only in mcpd logs. Omitted when mcpd is
   * unreachable/unauthorized (fetch returns null).
   */
  async function renderSecretBackendsSection(
    backendsPromise: Promise<SecretBackendInfo[] | null>,
    ansi: boolean,
  ): Promise<void> {
    const backends = await backendsPromise;
    if (backends === null || backends.length === 0) return;
    const parts = backends.map((b) => {
      const err = b.tokenMeta?.lastRotationError;
      const tag = b.isDefault ? `${b.name}*` : b.name;
      if (err) {
        const short = err.split('\n')[0]?.slice(0, 80) ?? 'error';
        return ansi ? `${tag} ${RED}✗ ${short}${RESET}` : `${tag} ✗ ${short}`;
      }
      return ansi ? `${tag} ${GREEN}✓${RESET}` : `${tag} ✓`;
    });
    log(`Secrets:    ${parts.join(', ')}`);
  }

  /**
   * Print a "Server LLMs:" section listing mcpd-managed Llm rows by tier
   * with a per-LLM "say hi" liveness probe. Distinct from the mcplocal-side
   * providers shown by the existing "LLM:" lines above. The caller awaits a
   * pre-launched promise so this doesn't add fetch round-trips, but the
   * probe itself runs here (after the user has the rest of the screen).
   */
  async function renderServerLlmsSection(
    serverLlmsPromise: Promise<ServerLlm[] | null>,
    mcpdUrl: string,
    token: string | null,
    ansi: boolean,
  ): Promise<void> {
    const llms = await serverLlmsPromise;
    if (llms === null) {
      // Auth failure / unreachable mcpd: fold into the existing mcpd-status
      // signal we already printed; nothing more to say here.
      return;
    }
    if (llms.length === 0) {
      log(`Server LLMs: none registered  ${ansi ? DIM : ''}(use 'mcpctl create llm')${ansi ? RESET : ''}`);
      return;
    }

    log(`Server LLMs: ${String(llms.length)} registered ${ansi ? DIM : ''}(probing live "say hi"...)${ansi ? RESET : ''}`);

    // Run all probes in parallel — one slow LLM doesn't block the others.
    const healthByName = new Map<string, ServerLlmHealth>();
    await Promise.all(llms.map(async (l) => {
      healthByName.set(l.name, await probeServerLlm(mcpdUrl, l.name, token));
    }));

    const byTier = new Map<string, ServerLlm[]>();
    for (const l of llms) {
      const arr = byTier.get(l.tier) ?? [];
      arr.push(l);
      byTier.set(l.tier, arr);
    }

    // Print tiers in a stable order — fast/heavy first, then anything else.
    const tierOrder = ['fast', 'heavy', ...[...byTier.keys()].filter((t) => t !== 'fast' && t !== 'heavy').sort()];
    for (const tier of tierOrder) {
      const rows = byTier.get(tier);
      if (rows === undefined || rows.length === 0) continue;
      const formatted = rows.map((r) => formatServerLlmLine(r, healthByName.get(r.name), ansi));
      log(`  ${tier.padEnd(6)} ${formatted.join('\n          ')}`);
    }
  }
}

/**
 * Format a single server-LLM row plus its health-probe outcome on one line.
 * Exported via module scope (not closure) so it stays cheap to test in
 * isolation; takes \`ansi\` rather than reading a TTY at call time.
 */
function formatServerLlmLine(r: ServerLlm, h: ServerLlmHealth | undefined, ansi: boolean): string {
  const upstream = r.url !== '' ? r.url : 'provider default';
  const auth = r.apiKeyRef ? `key:${r.apiKeyRef.name}/${r.apiKeyRef.key}` : 'no key';
  let healthStr: string;
  if (h === undefined) {
    healthStr = ansi ? `${DIM}? probe skipped${RESET}` : '? probe skipped';
  } else if (h.ok) {
    const reply = h.say !== undefined ? `"${h.say}"` : 'ok';
    const ms = `${String(h.ms)}ms`;
    healthStr = ansi ? `${GREEN}✓ ${reply} ${DIM}${ms}${RESET}` : `✓ ${reply} ${ms}`;
  } else {
    const err = h.error ?? 'failed';
    healthStr = ansi ? `${RED}✗ ${err}${RESET}` : `✗ ${err}`;
  }
  const meta = `${r.type} → ${r.model}`;
  // Two-line layout: name + health on top, dim metadata indented below.
  // Keeps the at-a-glance signal (✓/✗) close to the LLM name.
  const head = `${r.name}  ${healthStr}`;
  const tail = ansi
    ? `${DIM}${meta}  ${upstream}  ${auth}${RESET}`
    : `${meta}  ${upstream}  ${auth}`;
  return `${head}\n            ${tail}`;
}
