/**
 * Synchronous config file generation for setup command.
 *
 * Reuses the CONFIG_TEMPLATE from config-init.ts pattern but provides
 * a synchronous API suitable for the setup command flow.
 *
 * @module cli/setup-config
 * (Source: Issue #1252 - Setup auto-generates nexus-agents.yaml)
 */

import { copyFileSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { getErrorMessage } from '../core/index.js';

/** Default configuration file name. */
const DEFAULT_CONFIG_FILE = 'nexus-agents.yaml';

/**
 * Path setup writes new configs to (epic #2872). The config loader checks
 * `.nexus-agents/nexus-agents.yaml` ahead of the legacy root-level location,
 * so writing here is forward-compatible. Existing root-level configs keep
 * working without action (loader still falls back to them).
 */
const DEFAULT_CONFIG_REL_PATH = `.nexus-agents/${DEFAULT_CONFIG_FILE}`;

/** Result of the config generation step. */
export interface ConfigStepResult {
  readonly success: boolean;
  readonly path: string;
  readonly created: boolean;
  readonly message: string;
}

/**
 * Minimal YAML config template for setup command.
 * Intentionally brief — just enough to get started.
 * Users can run `nexus-agents config init` for the full template.
 */
const SETUP_CONFIG_TEMPLATE = `# Nexus Agents Configuration
# Generated by: nexus-agents setup
# Full template: nexus-agents config init

models:
  default: claude-sonnet-4

experts:
  builtin: true

logging:
  level: info
  format: json
`;

/**
 * Generates a nexus-agents.yaml config file synchronously.
 *
 * @param projectRoot - Directory to create config in.
 * @param force - Overwrite existing config.
 * @param dryRun - Report what would happen without writing.
 */
export function runConfigInitSync(
  projectRoot: string,
  force: boolean,
  dryRun: boolean
): ConfigStepResult {
  // Prefer the dotdir location for new configs. Per #2877: if a legacy
  // root-level nexus-agents.yaml already exists, keep editing it in place
  // rather than silently moving the user's config — the migrate command
  // (#2879) is the explicit way to relocate. New installs land in the dotdir.
  const legacyPath = resolve(projectRoot, DEFAULT_CONFIG_FILE);
  const outputPath = existsSync(legacyPath)
    ? legacyPath
    : resolve(projectRoot, DEFAULT_CONFIG_REL_PATH);

  if (existsSync(outputPath) && !force) {
    return {
      success: true,
      path: outputPath,
      created: false,
      message: 'Config already exists (use --force to overwrite)',
    };
  }

  if (dryRun) {
    return {
      success: true,
      path: outputPath,
      created: true,
      message: `Would create: ${outputPath}`,
    };
  }

  const backup = ensureBackup(outputPath);
  if ('error' in backup) return backup.error;

  try {
    // Ensure parent dir exists — needed for the new dotdir location since
    // .nexus-agents/ may not yet exist on a fresh repo.
    mkdirSync(dirname(outputPath), { recursive: true });
    writeFileSync(outputPath, SETUP_CONFIG_TEMPLATE, 'utf-8');
    const message =
      backup.path !== undefined
        ? `Created: ${outputPath} (backup saved at ${backup.path})`
        : `Created: ${outputPath}`;
    return { success: true, path: outputPath, created: true, message };
  } catch (error: unknown) {
    return {
      success: false,
      path: outputPath,
      created: false,
      message: `Failed: ${getErrorMessage(error)}`,
    };
  }
}

/**
 * Saves a timestamped backup of an existing config file before overwrite (#2183).
 *
 * Returns `{ path }` with the backup path (or undefined if no existing file)
 * on success, or `{ error }` with a populated `ConfigStepResult` on failure.
 * Failure to write the backup aborts the overwrite — better to keep the
 * user's customizations intact than to lose them silently.
 */
function ensureBackup(
  outputPath: string
): { path: string | undefined } | { error: ConfigStepResult } {
  if (!existsSync(outputPath)) return { path: undefined };
  const backupPath = `${outputPath}.bak.${String(Date.now())}`;
  try {
    copyFileSync(outputPath, backupPath);
    return { path: backupPath };
  } catch (err: unknown) {
    return {
      error: {
        success: false,
        path: outputPath,
        created: false,
        message: `Failed to back up existing config: ${getErrorMessage(err)}`,
      },
    };
  }
}
