import type { FillerQuestion, FillerAnswerValue } from "@/types/filler";

export interface ValidationResult {
  valid: boolean;
  message?: string;
}

/** Validate an answer against question type and validationConfig. */
export function validateFillerAnswer(
  question: FillerQuestion,
  answer: FillerAnswerValue
): ValidationResult {
  const isEmpty =
    answer === null ||
    answer === undefined ||
    answer === "" ||
    (Array.isArray(answer) && answer.length === 0);

  if (question.isRequired && isEmpty) {
    return { valid: false, message: "This question is required." };
  }

  if (isEmpty) return { valid: true };

  if (
    question.type === "matrix" &&
    typeof answer === "object" &&
    !Array.isArray(answer)
  ) {
    const rows = question.optionsConfig?.rows ?? [];
    const answered = answer as Record<string, string>;
    if (question.isRequired) {
      const missing = rows.some((row) => !answered[row]);
      if (missing) {
        return { valid: false, message: "Please answer every row." };
      }
    }
  }

  if (question.type === "open_text" && typeof answer === "string") {
    const cfg = question.validationConfig;
    if (cfg?.minLength && answer.length < cfg.minLength) {
      return {
        valid: false,
        message: `Minimum ${cfg.minLength} characters required.`,
      };
    }
    if (cfg?.maxLength && answer.length > cfg.maxLength) {
      return {
        valid: false,
        message: `Maximum ${cfg.maxLength} characters allowed.`,
      };
    }
    if (cfg?.responseType === "email" && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(answer)) {
      return { valid: false, message: "Enter a valid email address." };
    }
    if (cfg?.responseType === "number" && Number.isNaN(Number(answer))) {
      return { valid: false, message: "Enter a valid number." };
    }
  }

  if (
    (question.type === "rating" || question.type === "nps") &&
    typeof answer === "number"
  ) {
    const min = question.optionsConfig?.minRating ?? (question.type === "nps" ? 0 : 1);
    const max = question.optionsConfig?.maxRating ?? (question.type === "nps" ? 10 : 5);
    if (answer < min || answer > max) {
      return { valid: false, message: `Select a value between ${min} and ${max}.` };
    }
  }

  if (question.type === "checkbox" && Array.isArray(answer)) {
    const cfg = question.validationConfig;
    if (cfg?.minSelections && answer.length < cfg.minSelections) {
      return {
        valid: false,
        message: `Select at least ${cfg.minSelections} option${cfg.minSelections === 1 ? "" : "s"}.`,
      };
    }
    if (cfg?.maxSelections && answer.length > cfg.maxSelections) {
      return {
        valid: false,
        message: `Select at most ${cfg.maxSelections} option${cfg.maxSelections === 1 ? "" : "s"}.`,
      };
    }
  }

  if (
    question.type === "dropdown" &&
    question.optionsConfig?.allowMultiple &&
    Array.isArray(answer)
  ) {
    const cfg = question.validationConfig;
    if (cfg?.minSelections && answer.length < cfg.minSelections) {
      return {
        valid: false,
        message: `Select at least ${cfg.minSelections} option${cfg.minSelections === 1 ? "" : "s"}.`,
      };
    }
    if (cfg?.maxSelections && answer.length > cfg.maxSelections) {
      return {
        valid: false,
        message: `Select at most ${cfg.maxSelections} option${cfg.maxSelections === 1 ? "" : "s"}.`,
      };
    }
  }

  return { valid: true };
}

/** Normalize answer value for JSON storage in Answer.value. */
export function normalizeAnswerForStorage(
  question: FillerQuestion,
  answer: FillerAnswerValue
): unknown {
  if (answer === null || answer === undefined) return null;

  switch (question.type) {
    case "multiple_choice":
    case "checkbox":
    case "dropdown":
      return { choice: answer };
    case "rating":
    case "nps":
      return { score: answer };
    case "open_text":
      return { text: answer };
    case "date_time":
      return { datetime: answer };
    case "file_upload":
      return { fileName: answer };
    case "matrix":
      return { matrix: answer };
    default:
      return answer;
  }
}
