import type { ConditionalRule, FormAnswers, Question } from './types'

/** Returns true if the question should be shown given the current answers. */
export function isQuestionVisible(
  question: Question,
  answers: FormAnswers
): boolean {
  const rules = question.conditional_rules
  if (!rules || rules.length === 0) return true
  // All rules must pass (AND semantics)
  return rules.every((rule) => evaluateRule(rule, answers))
}

/** Normalizes if_question to an array of codes regardless of rule shape. */
export function ruleQuestionCodes(rule: ConditionalRule): string[] {
  return Array.isArray(rule.if_question) ? rule.if_question : [rule.if_question]
}

function evaluateRule(rule: ConditionalRule, answers: FormAnswers): boolean {
  if (rule.op === 'eq') {
    return answers[rule.if_question as string] === rule.value
  }
  if (rule.op === 'eq_any') {
    return ruleQuestionCodes(rule).some((code) => answers[code] === rule.value)
  }
  return false
}

/**
 * Returns the codes of questions that will become hidden when `triggerCode`
 * changes to `newValue`. Used to clear those answers reactively.
 */
export function getHiddenCodes(
  triggerCode: string,
  newValue: string | string[] | number | null,
  questions: Question[],
  currentAnswers: FormAnswers
): string[] {
  const projected = { ...currentAnswers, [triggerCode]: newValue }
  return questions
    .filter((q) => {
      if (!q.conditional_rules?.length) return false
      const dependsOnTrigger = q.conditional_rules.some((r) =>
        ruleQuestionCodes(r).includes(triggerCode)
      )
      if (!dependsOnTrigger) return false
      return !isQuestionVisible(q, projected)
    })
    .map((q) => q.code)
}

/** All trigger codes in the survey (questions that have dependents). */
export function getTriggerCodes(questions: Question[]): Set<string> {
  const triggers = new Set<string>()
  for (const q of questions) {
    for (const rule of q.conditional_rules ?? []) {
      for (const code of ruleQuestionCodes(rule)) triggers.add(code)
    }
  }
  return triggers
}
