import assert from "node:assert/strict";
import test from "node:test";

import { formatAnswers, normalizeQuestions, orderedAnswers } from "../src/normalize.ts";
import type { UserAnswer } from "../src/types.ts";

test("normalizes select and text questions with bounded defaults", () => {
  const questions = normalizeQuestions([
    {
      id: "language",
      label: " Language ",
      prompt: " Choose a language ",
      type: "select",
      options: [{ value: "ts", label: " TypeScript " }],
    },
    {
      id: "notes",
      prompt: "Anything else?",
      type: "text",
      required: false,
    },
  ]);

  assert.deepEqual(questions[0], {
    id: "language",
    label: "Language",
    prompt: "Choose a language",
    type: "select",
    options: [{ value: "ts", label: "TypeScript" }],
    allowCustom: true,
    required: true,
  });
  assert.equal(questions[1]?.label, "Q2");
  assert.equal(questions[1]?.allowCustom, false);
  assert.equal(questions[1]?.required, false);
});

test("rejects invalid ids, duplicate ids, invalid option combinations, and duplicate values", () => {
  assert.throws(() => normalizeQuestions([{ id: "bad id", prompt: "Bad", type: "text" }]), /must start with a letter/);
  assert.throws(() => normalizeQuestions([null as never]), /must be an object/);
  assert.throws(() => normalizeQuestions([{ id: "bad_flag", prompt: "Bad", type: "text", required: "yes" as never }]), /must be a boolean/);
  assert.throws(() => normalizeQuestions([
    { id: "same", prompt: "One", type: "text" },
    { id: "same", prompt: "Two", type: "text" },
  ]), /duplicate question id/);
  assert.throws(() => normalizeQuestions([{ id: "pick", prompt: "Pick", type: "select" }]), /at least one option/);
  assert.throws(() => normalizeQuestions([{ id: "text", prompt: "Write", type: "text", options: [{ value: "x", label: "X" }] }]), /must not define options/);
  assert.throws(() => normalizeQuestions([{
    id: "pick",
    prompt: "Pick",
    type: "select",
    options: [{ value: "x", label: "X" }, { value: "x", label: "Again" }],
  }]), /duplicate option value/);
});

test("orders and formats answers by question order", () => {
  const questions = normalizeQuestions([
    { id: "first", prompt: "First?", type: "text" },
    { id: "second", prompt: "Second?", type: "select", options: [{ value: "yes", label: "Yes" }] },
    { id: "third", prompt: "Third?", type: "text", required: false },
  ]);
  const answer = (id: string, overrides: Partial<UserAnswer>): UserAnswer => ({
    id,
    question: `${id}?`,
    type: "text",
    answer: id,
    value: id,
    label: id,
    custom: false,
    skipped: false,
    ...overrides,
  });
  const answers = new Map<string, UserAnswer>([
    ["third", answer("third", { answer: "", value: "", label: "Skipped", skipped: true })],
    ["second", answer("second", { type: "select", answer: "Yes", value: "yes", label: "Yes" })],
    ["first", answer("first", { answer: "hello", value: "hello", label: "hello", custom: true })],
  ]);

  const ordered = orderedAnswers(questions, answers);
  assert.deepEqual(ordered.map((item) => item.id), ["first", "second", "third"]);
  assert.equal(formatAnswers(ordered), [
    "first: user wrote: hello",
    "second: user selected: Yes (value: yes)",
    "third: skipped",
  ].join("\n"));
});
