import { ARCHETYPE_IDS, ARCHETYPE_LETTERS, type Answer, type ArchetypeId, type Question } from './types';

/**
 * A result code is the version digit followed by one character per question:
 * "1"–"5" for a Likert answer, or the archetype letter ("A"–"H") for a scenario answer.
 * It is URL-safe, holds no personal data, and lets a result be re-scored anywhere.
 */
export const CODE_VERSION = '1';

const LETTER_TO_ARCHETYPE = Object.fromEntries(
  ARCHETYPE_IDS.map((id) => [ARCHETYPE_LETTERS[id], id]),
) as Record<string, ArchetypeId>;

export function encodeAnswers(questions: Question[], answers: Answer[]): string {
  if (answers.length !== questions.length) {
    throw new Error(`Expected ${questions.length} answers, received ${answers.length}`);
  }
  const body = questions.map((question, i) => {
    const answer = answers[i];
    if (question.kind === 'likert') {
      if (typeof answer !== 'number' || !Number.isInteger(answer) || answer < 1 || answer > 5) {
        throw new Error(`Invalid answer for ${question.id}`);
      }
      return String(answer);
    }
    if (typeof answer !== 'string' || !question.options.some((o) => o.archetype === answer)) {
      throw new Error(`Invalid answer for ${question.id}`);
    }
    return ARCHETYPE_LETTERS[answer];
  });
  return CODE_VERSION + body.join('');
}

/** Returns the answers for a valid code, or null for anything malformed. */
export function decodeAnswers(questions: Question[], code: string | null | undefined): Answer[] | null {
  if (!code || code.length !== questions.length + 1 || code[0] !== CODE_VERSION) return null;
  const answers: Answer[] = [];
  for (let i = 0; i < questions.length; i++) {
    const question = questions[i];
    const char = code[i + 1];
    if (question.kind === 'likert') {
      if (!/^[1-5]$/.test(char)) return null;
      answers.push(Number(char));
    } else {
      const id = LETTER_TO_ARCHETYPE[char];
      if (!id || !question.options.some((o) => o.archetype === id)) return null;
      answers.push(id);
    }
  }
  return answers;
}
