(function initFivaValidators(global) {
  "use strict";

  if (global.FIVA?.Validators) return;

  const FIELD_LABEL_WORDS = /\b(upload|document|passport|visa|application|registration|details|field|required|email|country|mission|nationality|purpose|gender|surname|given|name|birth|arrival|issue|expiry|pdf|jpg|jpeg|png)\b/i;
  const DATE_FIELDS = new Set(["dateOfBirth", "expectedArrivalDate", "passportIssueDate", "passportExpiryDate"]);
  const NAME_FIELDS = new Set(["fullName", "givenNames", "givenName", "surname", "cityOfBirth"]);

  function compact(value = "") {
    return String(value || "").replace(/\s+/g, " ").trim();
  }

  function normalize(value = "") {
    return compact(value)
      .toLowerCase()
      .replace(/&/g, " and ")
      .replace(/[^a-z0-9]+/g, " ")
      .replace(/\s+/g, " ")
      .trim();
  }

  function dateParts(value = "") {
    const strict = global.FIVA?.StrictDobValidator?.parseDate?.(value);
    if (strict?.display) {
      const [day, month, year] = strict.display.split("/").map(Number);
      return { day, month, year };
    }
    const source = compact(value);
    const iso = source.match(/^(\d{4})-(\d{2})-(\d{2})$/);
    if (iso) return { day: Number(iso[3]), month: Number(iso[2]), year: Number(iso[1]) };
    const display = source.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
    if (display) return { day: Number(display[1]), month: Number(display[2]), year: Number(display[3]) };
    return null;
  }

  function validCalendarDate(value = "") {
    const parts = dateParts(value);
    if (!parts || parts.year < 1900 || parts.year > 2100 || parts.month < 1 || parts.month > 12 || parts.day < 1 || parts.day > 31) return false;
    const date = new Date(Date.UTC(parts.year, parts.month - 1, parts.day));
    return date.getUTCFullYear() === parts.year
      && date.getUTCMonth() === parts.month - 1
      && date.getUTCDate() === parts.day;
  }

  function displayDate(value = "") {
    const parts = dateParts(value);
    if (!parts || !validCalendarDate(value)) return "";
    return `${String(parts.day).padStart(2, "0")}/${String(parts.month).padStart(2, "0")}/${String(parts.year).padStart(4, "0")}`;
  }

  function isEmail(value = "") {
    return /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(compact(value));
  }

  function isPassport(value = "") {
    return /^[A-Z0-9]{6,16}$/i.test(compact(value).replace(/[^A-Z0-9]/gi, ""));
  }

  function fileNameStem(fileName = "") {
    return normalize(String(fileName || "").replace(/\.(pdf|png|jpe?g)$/i, ""));
  }

  function validName(value = "", source = {}) {
    const sourceValue = compact(value);
    const normalized = normalize(sourceValue);
    if (!normalized || normalized.length < 2) return false;
    if (/\.(pdf|png|jpe?g)\b/i.test(sourceValue)) return false;
    if (/\d{4,}/.test(sourceValue)) return false;
    if (!/[a-z]/i.test(sourceValue)) return false;
    if (FIELD_LABEL_WORDS.test(sourceValue) && normalized.split(" ").length <= 3) return false;

    const stem = fileNameStem(source.fileName);
    if (stem && (normalized === stem || stem.includes(normalized) || normalized.includes(stem))) return false;
    return true;
  }

  function validateField(fieldKey, value, source = {}) {
    const sourceValue = compact(value);
    if (!sourceValue) return { ok: false, value: "", reason: "missing" };

    if (DATE_FIELDS.has(fieldKey) || fieldKey === "dob" || fieldKey === "arrivalDate") {
      const normalizedDate = displayDate(sourceValue);
      return normalizedDate
        ? { ok: true, value: normalizedDate }
        : { ok: false, value: "", reason: "invalid date" };
    }

    if (fieldKey === "email" || fieldKey === "reEnterEmail") {
      const match = sourceValue.match(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i)?.[0] || "";
      return isEmail(match)
        ? { ok: true, value: match.toLowerCase() }
        : { ok: false, value: "", reason: "invalid email" };
    }

    if (fieldKey === "passportNumber") {
      const passport = sourceValue.toUpperCase().replace(/[^A-Z0-9]/g, "");
      return isPassport(passport)
        ? { ok: true, value: passport }
        : { ok: false, value: "", reason: "invalid passport" };
    }

    if (NAME_FIELDS.has(fieldKey)) {
      return validName(sourceValue, source)
        ? { ok: true, value: sourceValue }
        : { ok: false, value: "", reason: "invalid name" };
    }

    return { ok: true, value: sourceValue };
  }

  function sanitizeProfile(profile = {}, source = {}) {
    const next = {};
    Object.entries(profile || {}).forEach(([fieldKey, value]) => {
      if (fieldKey.startsWith("__")) return;
      const result = validateField(fieldKey, value, source);
      if (result.ok) next[fieldKey] = result.value;
    });
    return next;
  }

  const Validators = Object.freeze({
    compact,
    displayDate,
    isEmail,
    isPassport,
    normalize,
    sanitizeProfile,
    validateField,
    validCalendarDate,
    validName
  });

  global.FIVA = Object.assign(global.FIVA || {}, { Validators });
})(typeof globalThis !== "undefined" ? globalThis : this);
