/**
 * SOP-to-YAML converter for the Ion workflow engine.
 *
 * Converts a parsed `SopDocument` into a YAML workflow definition string
 * that can be fed back into the Ion YAML loader.
 */

import type { SopDocument } from './sop-parser.js';

/** Convert a title string to kebab-case for use as a YAML identifier. */
function toKebabCase(title: string): string {
  return title
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-') // non-alphanumeric → hyphen
    .replace(/^-+|-+$/g, ''); // strip leading/trailing hyphens
}

/**
 * Indent every line of a multi-line string by the given number of spaces.
 * Empty lines are preserved without extra indentation.
 */
function indentBlock(text: string, spaces: number): string {
  const prefix = ' '.repeat(spaces);
  return text
    .split('\n')
    .map((line) => (line.length > 0 ? prefix + line : line))
    .join('\n');
}

/**
 * Convert a parsed `SopDocument` into a YAML workflow definition string.
 *
 * The output is valid YAML that can be loaded by the Ion YAML loader.
 * Steps become sequential prompt nodes with `depends_on` linking.
 * Constraints are appended to the prompt body as plain text.
 * Only `prompt:` nodes are emitted — SOP is conversation-only.
 *
 * @param sop - The parsed SOP document.
 * @returns A YAML string representing the workflow.
 */
export function convertSopToWorkflowYaml(sop: SopDocument): string {
  const name = toKebabCase(sop.title);
  const lines: string[] = [];

  if (sop.parameters.length > 0) {
    lines.push('# Parameters:');
    for (const param of sop.parameters) {
      const tag = param.type === 'required' ? 'required' : 'optional';
      const defaultPart = param.default ? `, default: ${param.default}` : '';
      lines.push(`#   ${param.name} (${tag}${defaultPart}): ${param.description}`);
    }
    lines.push('');
  }

  lines.push(`name: ${name}`);
  lines.push(`description: |`);
  lines.push(indentBlock(sop.overview || 'No description provided.', 2));
  lines.push('');

  lines.push('nodes:');

  for (let i = 0; i < sop.steps.length; i++) {
    const step = sop.steps[i]!;
    const stepId = `step_${step.number}`;
    const isFirst = i === 0;

    // Build the prompt body: step body + constraints (if any)
    let promptBody = step.body;
    if (step.constraints) {
      promptBody += `\n\nConstraints:\n${step.constraints}`;
    }

    lines.push(`  - id: ${stepId}`);
    lines.push(`    prompt: |`);
    lines.push(indentBlock(promptBody, 6));

    if (isFirst) {
      lines.push(`    depends_on: []`);
    } else {
      const prevStep = sop.steps[i - 1]!;
      lines.push(`    depends_on: [step_${prevStep.number}]`);
    }

    // Blank line between nodes (but not after the last one)
    if (i < sop.steps.length - 1) {
      lines.push('');
    }
  }

  return lines.join('\n') + '\n';
}