#!/usr/bin/env node
/**
 * question-slots — трекинг заданных вопросов разговорной фазы как СЛОТОВ с id
 * (условие R7 spec 2026-06-05): механическая проверка «нет повисших вопросов»
 * работает только если вопрос помечается слотом (задан/отвечен), а не вольным
 * текстом. Чистый модуль, иммутабельные операции ($0, без LLM).
 */

function isNonEmptyString(v) { return typeof v === 'string' && v.trim().length > 0; }

/** Добавить заданный вопрос (новый слот answered:false). id — непустой уникальный. */
export function addQuestion(slots, { id, text } = {}) {
  const list = Array.isArray(slots) ? slots : [];
  if (!isNonEmptyString(id)) throw new Error('question id: непустая строка обязательна');
  if (!isNonEmptyString(text)) throw new Error('question text: непустая строка обязательна');
  if (list.some((s) => s.id === id)) throw new Error(`question id дублируется: ${id}`);
  return [...list, { id, text, answered: false, answer: null }];
}

/** Пометить вопрос отвеченным (непустой ответ). Неизвестный id → ошибка. */
export function answerQuestion(slots, id, answer) {
  const list = Array.isArray(slots) ? slots : [];
  if (!list.some((s) => s.id === id)) throw new Error(`неизвестный question id: ${id}`);
  if (!isNonEmptyString(answer)) throw new Error('answer: непустая строка обязательна');
  return list.map((s) => (s.id === id ? { ...s, answered: true, answer } : s));
}

/** Повисшие вопросы — заданные, но не отвеченные. */
export function hangingQuestions(slots) {
  return (Array.isArray(slots) ? slots : []).filter((s) => !s.answered);
}

/** Ни один заданный вопрос не повис (пустой список → true, вопросов нет). */
export function allAnswered(slots) {
  return hangingQuestions(slots).length === 0;
}
