/**
 * Serialization and formatting helpers for CLI commands and args.
 *
 * Used by the `list` command, Commander --help, and build-manifest.
 * Separated from registry.ts to keep the registry focused on types + registration.
 */

import type { Arg, CliCommand } from './registry.js';
import { fullName, strategyLabel } from './registry.js';

// ── Serialization ───────────────────────────────────────────────────────────

export type SerializedArg = {
  name: string;
  type: string;
  required: boolean;
  valueRequired: boolean;
  positional: boolean;
  choices: string[];
  default: unknown;
  help: string;
};

/** Stable arg schema — every field is always present (no sparse objects). */
export function serializeArg(a: Arg): SerializedArg {
  return {
    name: a.name,
    type: a.type ?? 'string',
    required: !!a.required,
    valueRequired: !!a.valueRequired,
    positional: !!a.positional,
    choices: a.choices ?? [],
    default: a.default ?? null,
    help: a.help ?? '',
  };
}

/** Full command metadata for structured output (json/yaml). */
export function serializeCommand(cmd: CliCommand) {
  return {
    command: fullName(cmd),
    site: cmd.site,
    name: cmd.name,
    aliases: cmd.aliases ?? [],
    description: cmd.description,
    access: cmd.access,
    strategy: strategyLabel(cmd),
    browser: !!cmd.browser,
    args: cmd.args.map(serializeArg),
    columns: cmd.columns ?? [],
    domain: cmd.domain ?? null,
    example: formatCommandExample(cmd),
    defaultFormat: cmd.defaultFormat ?? null,
    siteSession: cmd.siteSession ?? null,
  };
}

// ── Formatting ──────────────────────────────────────────────────────────────

/** Human-readable arg summary: `<required> [optional]` style. */
export function formatArgSummary(args: Arg[]): string {
  return args
    .map(a => {
      if (a.positional) return a.required ? `<${a.name}>` : `[${a.name}]`;
      return a.required ? `--${a.name}` : `[--${a.name}]`;
    })
    .join(' ');
}

function summarizeChoices(choices: string[]): string {
  if (choices.length <= 4) return choices.join(', ');
  return `${choices.slice(0, 4).join(', ')}, ... (+${choices.length - 4} more)`;
}

function formatValuePlaceholder(name: string): string {
  return `<${name}>`;
}

/** Agent-facing canonical invocation. Adapter authors may override with `example`. */
export function formatCommandExample(cmd: CliCommand): string {
  if (cmd.example?.trim()) return cmd.example.trim();
  const parts = ['opencli', cmd.site, cmd.name];
  for (const arg of cmd.args) {
    if (arg.positional && arg.required) {
      parts.push(formatValuePlaceholder(arg.name));
    }
  }
  for (const arg of cmd.args) {
    if (arg.positional || !arg.required) continue;
    parts.push(`--${arg.name}`);
    if (arg.type !== 'bool' && arg.type !== 'boolean') parts.push(formatValuePlaceholder(arg.name));
  }
  parts.push('-f', 'yaml');
  return parts.join(' ');
}

/** Generate the --help appendix showing registry metadata not exposed by Commander. */
export function formatRegistryHelpText(cmd: CliCommand): string {
  const lines: string[] = [];
  const choicesArgs = cmd.args.filter(a => a.choices?.length);
  for (const a of choicesArgs) {
    const prefix = a.positional ? `<${a.name}>` : `--${a.name}`;
    const def = a.default != null ? `  (default: ${a.default})` : '';
    lines.push(`  ${prefix}: ${summarizeChoices(a.choices!)}${def}`);
  }
  const meta: string[] = [];
  meta.push(`Access: ${cmd.access}`);
  meta.push(`Browser: ${cmd.browser ? 'yes' : 'no'}`);
  if (cmd.domain) meta.push(`Domain: ${cmd.domain}`);
  if (cmd.defaultFormat) meta.push(`Default format: ${cmd.defaultFormat}`);
  if (cmd.aliases?.length) meta.push(`Aliases: ${cmd.aliases.join(', ')}`);
  lines.push(meta.join(' | '));
  lines.push(`Example: ${formatCommandExample(cmd)}`);
  if (cmd.columns?.length) lines.push(`Output columns: ${cmd.columns.join(', ')}`);
  return '\n' + lines.join('\n') + '\n';
}
