/**
 * Resolve PTW question type labels from master data into admin UI kinds.
 */

import {
  AUTHORIZATION_QUESTION_TYPE_ID,
  RISK_ASSESSMENT_QUESTION_TYPE_ID,
  TEXT_QUESTION_TYPE_ID
} from "../config/ptwQuestionTypes.js";

export const QUESTION_TYPE_KIND = {
  TEXT: "text",
  NUMBER: "number",
  YES_NO: "yesNo",
  OPTIONS: "options",
  IMAGE: "image",
  AUTHORIZATION: "authorization",
  RISK_ASSESSMENT: "riskAssessment"
};

/** How option-based questions are answered (admin preview + future permit UI). */
export const OPTIONS_DISPLAY_MODE = {
  MCQ_RADIO: "mcqRadio",
  MMCQ_CHECKBOX: "mmcqCheckbox",
  SINGLE_DROPDOWN: "singleDropdown",
  MULTI_DROPDOWN: "multiDropdown"
};

function normalizeTypeName(label) {
  return String(label || "").trim().toLowerCase();
}

export function getTypeLabel(typeId, questionTypeOptions = []) {
  if (!typeId) return "";
  const match = questionTypeOptions.find((o) => String(o.value) === String(typeId));
  return match?.label ?? "";
}

function typeNameFromId(typeId, questionTypeOptions) {
  return normalizeTypeName(getTypeLabel(typeId, questionTypeOptions));
}

/**
 * @returns {"text"|"number"|"yesNo"|"options"|"image"|"authorization"|null}
 */
export function resolveQuestionTypeKind(
  typeId,
  questionTypeOptions = [],
  typeNameOverride = null
) {
  if (isAuthorizationQuestionType(typeId, questionTypeOptions, typeNameOverride)) {
    return QUESTION_TYPE_KIND.AUTHORIZATION;
  }

  if (isRiskAssessmentQuestionType(typeId, questionTypeOptions, typeNameOverride)) {
    return QUESTION_TYPE_KIND.RISK_ASSESSMENT;
  }

  if (isTextQuestionType(typeId, questionTypeOptions, typeNameOverride)) {
    return QUESTION_TYPE_KIND.TEXT;
  }

  const name =
    typeNameOverride != null && String(typeNameOverride).trim()
      ? normalizeTypeName(typeNameOverride)
      : typeNameFromId(typeId, questionTypeOptions);
  if (!name) return null;

  if (
    name.includes("image") &&
    (name.includes("mark") || name.includes("attach"))
  ) {
    return QUESTION_TYPE_KIND.IMAGE;
  }

  if (name.includes("yes") && name.includes("no")) {
    return QUESTION_TYPE_KIND.YES_NO;
  }

  if (
    name.includes("dropdown") ||
    name.includes("mmcq") ||
    (name.includes("mcq") && !name.includes("mmcq"))
  ) {
    return QUESTION_TYPE_KIND.OPTIONS;
  }

  if (name === "number" || name.includes("number")) {
    return QUESTION_TYPE_KIND.NUMBER;
  }

  return null;
}

/**
 * @returns {keyof typeof OPTIONS_DISPLAY_MODE | null}
 */
function resolveDisplayModeFromName(name) {
  if (!name) return null;

  if (name.includes("mmcq")) {
    return OPTIONS_DISPLAY_MODE.MMCQ_CHECKBOX;
  }

  if (name.includes("dropdown") && name.includes("multiple")) {
    return OPTIONS_DISPLAY_MODE.MULTI_DROPDOWN;
  }

  if (name.includes("dropdown") || (name.includes("single") && name.includes("selection"))) {
    return OPTIONS_DISPLAY_MODE.SINGLE_DROPDOWN;
  }

  if (name.includes("mcq") && !name.includes("mmcq")) {
    return OPTIONS_DISPLAY_MODE.MCQ_RADIO;
  }

  return null;
}

export function resolveOptionsDisplayMode(
  typeId,
  questionTypeOptions = [],
  typeNameOverride = null
) {
  if (!typeId && !typeNameOverride) return null;

  const name =
    typeNameOverride != null && String(typeNameOverride).trim()
      ? normalizeTypeName(typeNameOverride)
      : typeNameFromId(typeId, questionTypeOptions);

  return resolveDisplayModeFromName(name);
}

export function getQuestionOptionLabels(question) {
  const opts = Array.isArray(question?.options) ? question.options : [];
  return opts
    .map((o) => (typeof o === "string" ? o : o.option ?? o._options ?? ""))
    .map((s) => String(s).trim())
    .filter(Boolean);
}

export function typeNeedsOptions(kind) {
  return kind === QUESTION_TYPE_KIND.OPTIONS;
}

export function normalizeOptionsArray(options) {
  const arr = Array.isArray(options) ? options : [];
  return arr.map((s) => String(s).trim()).filter(Boolean);
}

/** Hint text for the options builder based on display mode. */
export function getOptionsBuilderHint(typeId, questionTypeOptions = []) {
  const mode = resolveOptionsDisplayMode(typeId, questionTypeOptions);

  switch (mode) {
    case OPTIONS_DISPLAY_MODE.MMCQ_CHECKBOX:
      return "Add each choice separately. Respondents may choose multiple options using checkboxes (not a dropdown).";
    case OPTIONS_DISPLAY_MODE.MCQ_RADIO:
      return "Add each choice separately. Respondents choose one option using radio buttons (not a dropdown).";
    case OPTIONS_DISPLAY_MODE.MULTI_DROPDOWN:
      return "Add each choice separately. Respondents can select multiple options from a dropdown list.";
    case OPTIONS_DISPLAY_MODE.SINGLE_DROPDOWN:
      return "Add each choice separately. Respondents pick one option from a dropdown list.";
    default:
      return "Add each choice as a separate option.";
  }
}

export function isMcqRadioType(typeId, questionTypeOptions = []) {
  return (
    resolveOptionsDisplayMode(typeId, questionTypeOptions) ===
    OPTIONS_DISPLAY_MODE.MCQ_RADIO
  );
}

export function isMmcqCheckboxType(typeId, questionTypeOptions = []) {
  return (
    resolveOptionsDisplayMode(typeId, questionTypeOptions) ===
    OPTIONS_DISPLAY_MODE.MMCQ_CHECKBOX
  );
}

export function isImageQuestionType(typeId, questionTypeOptions = []) {
  return resolveQuestionTypeKind(typeId, questionTypeOptions) === QUESTION_TYPE_KIND.IMAGE;
}

function typeNameIndicatesAuthorization(name) {
  if (!name) return false;
  return (
    name.includes("authorisation acceptance") ||
    name.includes("authorization acceptance") ||
    /\bauthori[sz]ation\b/.test(name)
  );
}

export function isTextQuestionType(
  typeId,
  questionTypeOptions = [],
  typeNameOverride = null
) {
  const id = Number(typeId);
  if (Number.isFinite(id) && id === TEXT_QUESTION_TYPE_ID) {
    return true;
  }
  const name =
    typeNameOverride != null && String(typeNameOverride).trim()
      ? normalizeTypeName(typeNameOverride)
      : typeNameFromId(typeId, questionTypeOptions);
  return name === "text" || (name.includes("text") && !name.includes("context"));
}

/** Type-1 text questions the user fills in (excludes declaration copy for sign-off). */
export function isFillableTextQuestion(question, questionTypeOptions = []) {
  const typeOpts = question?.question_type
    ? [{ value: String(question.question_type_id ?? ""), label: question.question_type }]
    : questionTypeOptions;
  if (
    !isTextQuestionType(
      question?.question_type_id,
      typeOpts,
      question?.question_type
    )
  ) {
    return false;
  }
  return !isDeclarationTextQuestion(question, questionTypeOptions);
}

function typeNameIndicatesRiskAssessment(name) {
  if (!name) return false;
  const compact = name.replace(/\s+/g, "");
  return (
    compact === "riskassessment" ||
    compact === "risk_assessment" ||
    name.includes("risk assessment")
  );
}

export function isRiskAssessmentQuestionType(
  typeId,
  questionTypeOptions = [],
  typeNameOverride = null
) {
  const id = Number(typeId);
  if (Number.isFinite(id) && id === RISK_ASSESSMENT_QUESTION_TYPE_ID) {
    return true;
  }
  const name =
    typeNameOverride != null && String(typeNameOverride).trim()
      ? normalizeTypeName(typeNameOverride)
      : typeNameFromId(typeId, questionTypeOptions);
  return typeNameIndicatesRiskAssessment(name);
}

export function isAuthorizationQuestionType(
  typeId,
  questionTypeOptions = [],
  typeNameOverride = null
) {
  const id = Number(typeId);
  if (Number.isFinite(id) && id === AUTHORIZATION_QUESTION_TYPE_ID) {
    return true;
  }
  const name =
    typeNameOverride != null && String(typeNameOverride).trim()
      ? normalizeTypeName(typeNameOverride)
      : typeNameFromId(typeId, questionTypeOptions);
  return typeNameIndicatesAuthorization(name);
}

/** Role label for a type-9 sign-off row (first option, else question text). */
export function getSignoffRoleLabel(question) {
  const options = getQuestionOptionLabels(question);
  if (options.length) {
    return options[0].toUpperCase();
  }
  return String(question?.question || "Role").trim().toUpperCase() || "ROLE";
}

/** Long type-1 TEXT questions used as declaration copy above the sign-off table. */
export function isDeclarationTextQuestion(question, questionTypeOptions = []) {
  const typeOpts = question?.question_type
    ? [{ value: String(question.question_type_id ?? ""), label: question.question_type }]
    : questionTypeOptions;
  if (
    !isTextQuestionType(
      question?.question_type_id,
      typeOpts,
      question?.question_type
    )
  ) {
    return false;
  }
  if (
    isAuthorizationQuestionType(
      question?.question_type_id,
      typeOpts,
      question?.question_type
    )
  ) {
    return false;
  }
  return String(question?.question || "").trim().length > 80;
}

export function createEmptySignoffAnswer() {
  return { name: "", company: "", user_id: null };
}

export function parseSignoffAnswer(raw) {
  if (raw == null || raw === "") {
    return createEmptySignoffAnswer();
  }
  if (typeof raw === "object") {
    const userId = Number(raw.user_id);
    return {
      name: String(raw.name ?? ""),
      company: String(raw.company ?? ""),
      user_id: Number.isInteger(userId) && userId > 0 ? userId : null
    };
  }
  try {
    const parsed = JSON.parse(String(raw));
    if (!parsed || typeof parsed !== "object") {
      return createEmptySignoffAnswer();
    }
    const userId = Number(parsed.user_id);
    return {
      name: String(parsed.name ?? ""),
      company: String(parsed.company ?? ""),
      user_id: Number.isInteger(userId) && userId > 0 ? userId : null
    };
  } catch {
    return createEmptySignoffAnswer();
  }
}

export function serializeSignoffAnswer(data) {
  const parsed = parseSignoffAnswer(data);
  const payload = {
    name: parsed.name,
    company: parsed.company
  };
  if (parsed.user_id) {
    payload.user_id = parsed.user_id;
  }
  return JSON.stringify(payload);
}

/**
 * Validate type-9 sign-off answer JSON + signature blob.
 * @returns {string|null} Error message or null if valid
 */
export function validateSignoffAnswer(value, signatureFile, roleLabel = "this role") {
  const data = parseSignoffAnswer(value);
  const label = String(roleLabel || "this role").toLowerCase();

  if (!String(data.name ?? "").trim()) {
    return `Enter a name for ${label}.`;
  }
  if (!String(data.company ?? "").trim()) {
    return `Enter a company for ${label}.`;
  }
  if (!signatureFile) {
    return `Provide a signature for ${label}.`;
  }
  return null;
}

function readAnswerString(answers, questionId) {
  return String(answers?.[questionId] ?? answers?.[String(questionId)] ?? "").trim();
}

/**
 * Find the first Yes/No checklist question answered "No".
 * @returns {object|null} question row or null
 */
export function findChecklistNoAnswer(questions, answers, questionTypeOptions) {
  for (const q of questions || []) {
    const typeOpts = q?.question_type
      ? [{ value: String(q.question_type_id ?? ""), label: q.question_type }]
      : questionTypeOptions;
    const kind = resolveQuestionTypeKind(
      q.question_type_id,
      typeOpts,
      q.question_type
    );
    if (kind !== QUESTION_TYPE_KIND.YES_NO) continue;
    if (readAnswerString(answers, q.question_id).toLowerCase() === "no") {
      return q;
    }
  }
  return null;
}

/**
 * Block precaution checklist submission when any Yes/No answer is No.
 * @returns {string|null} Error message or null if valid
 */
export function validatePrecautionChecklistNoAnswers(questions, answers, questionTypeOptions) {
  const blocked = findChecklistNoAnswer(questions, answers, questionTypeOptions);
  if (!blocked) return null;
  return "This precaution checklist cannot be submitted while any answer is No. Resolve all No responses before continuing.";
}
