import { QuestionRow, TAnswerMethod } from "./survey";

interface ScanInputKwargs {
  clickAdd?: boolean;
}

// Radio/checkbox options render as `<input type="radio|checkbox"><label>Option Text</label>`
// pairs; matching by label prefix (rather than exact `value` attribute) mirrors how the old
// Question class worked, since option text sometimes carries trailing punctuation/whitespace.
function clickOption(webQuestionNode: HTMLElement, optionText: string): void {
  const labelNodes = webQuestionNode.querySelectorAll("label");

  for (const labelNode of labelNodes) {
    if (labelNode.innerText.trim().startsWith(optionText)) {
      const inputNode = labelNode.previousElementSibling as HTMLInputElement | null;
      // `.click()` toggles a checkbox (unlike a radio, which it just selects), so clicking an
      // already-checked checkbox would uncheck it. Only click when it isn't checked yet.
      if (inputNode !== null && !inputNode.checked) {
        inputNode.click();
      }
      return;
    }
  }

  throw new Error(`[clickOption] No option found matching text: '${optionText}'`);
}

// clickAdd (scan-input only) indicates that the `Add Item` button should be clicked
// after filling in the input box.
export function fillAnswerInput(
  method: TAnswerMethod,
  row: QuestionRow,
  value: string,
  kwargs?: Record<string, unknown>,
): void {
  const webQuestionNode = row.element.querySelector<HTMLElement>("[id$='WebQuestion']")!;

  if (method === "radio" || method === "checkbox") {
    clickOption(webQuestionNode, value);
    return;
  }

  // Convention: dispatch `change` then `blur` after setting the input's value, then
  // optionally click `button.add-item` for scan-input rows.
  const inputSelector =
    method === "scan-input" ? "input.item-search" : "textarea, input:not([type='hidden'])";
  const inputNode = webQuestionNode.querySelector<HTMLInputElement | HTMLTextAreaElement>(
    inputSelector,
  );

  if (inputNode === null) {
    throw new Error(`[fillAnswerInput] Could not find input for method: '${method}'`);
  }

  inputNode.value = value;
  inputNode.dispatchEvent(new Event("change", { bubbles: true }));
  inputNode.dispatchEvent(new Event("blur", { bubbles: true }));

  if (method === "scan-input") {
    const clickAdd = (kwargs as ScanInputKwargs | undefined)?.clickAdd;
    if (clickAdd === true) {
      webQuestionNode.querySelector<HTMLElement>("button.add-item")?.click();
    }
  }
}

export function readAnswer(row: QuestionRow): string | null {
  const webQuestionNode = row.element.querySelector<HTMLElement>("[id$='WebQuestion']")!;

  if (row.qType === "radio" || row.qType === "checkbox") {
    const checkedInput = webQuestionNode.querySelector<HTMLInputElement>(
      `input[type='${row.qType}']:checked`,
    );
    const labelNode = checkedInput?.nextElementSibling as HTMLElement | null;
    return labelNode?.innerText.trim() ?? null;
  }

  const inputSelector =
    row.qType === "scan-input" ? "input.item-search" : "textarea, input:not([type='hidden'])";
  const inputNode = webQuestionNode.querySelector<HTMLInputElement | HTMLTextAreaElement>(
    inputSelector,
  );
  const value = inputNode?.value.trim();

  return value === undefined || value === "" ? null : value;
}
