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

  if (global.FIVA?.ProfileNormalizer) {
    if (typeof module !== "undefined" && module.exports) module.exports = global.FIVA.ProfileNormalizer;
    return;
  }

  const STANDARD_KEYS = Object.freeze([
    "fullName",
    "country",
    "mission",
    "nationality",
    "dob",
    "email",
    "reEnterEmail",
    "arrivalDate",
    "expectedArrival",
    "visaType",
    "purpose",
    "surname",
    "givenName",
    "passportNumber",
    "passportIssueDate",
    "passportExpiryDate",
    "gender",
    "sourceConfidence"
  ]);

  const ALIASES = Object.freeze({
    country: [
      "country",
      "countryRegion",
      "country_region",
      "country/region",
      "country/region you are applying visa from",
      "applyingFromCountry",
      "applyingCountry",
      "visaCountry",
      "currentNationality",
      "nationality",
      "countryOfBirth",
      "nationalityByBirth"
    ],
    mission: [
      "mission",
      "indianMission",
      "indianMissionOffice",
      "indian mission",
      "indian mission/office",
      "missionOffice",
      "ivacCenter",
      "applicationCenter"
    ],
    nationality: [
      "nationality",
      "nationalityRegion",
      "nationality/region",
      "currentNationality",
      "nationalityByBirth"
    ],
    dob: ["dob", "dateOfBirth", "date of birth", "birthDate", "birth_date"],
    email: ["email", "emailId", "emailID", "email id", "emailAddress", "e-mail"],
    reEnterEmail: ["reEnterEmail", "confirmEmail", "re-enter email", "re enter email", "reEnterEmailId"],
    expectedArrival: ["expectedArrival", "expectedArrivalDate", "arrivalDate", "dateOfArrival", "expected date of arrival", "expected date of journey", "dateOfJourney"],
    visaType: ["visaType", "visaService", "visa service", "typeOfVisa", "type of visa required", "visaCategory"],
    purpose: ["purpose", "visaPurpose", "purposeOfVisit", "visitPurpose"],
    surname: ["surname", "lastName", "familyName", "family_name"],
    givenName: ["givenName", "givenNames", "given name", "given names", "firstName", "middleName"],
    passportNumber: ["passportNumber", "passportNo", "passport no", "passport number", "passNo", "pass_no"],
    passportIssueDate: ["passportIssueDate", "passport issue date", "dateOfIssue", "issueDate"],
    passportExpiryDate: ["passportExpiryDate", "passport expiry date", "dateOfExpiry", "expiryDate"],
    fullName: ["fullName", "full name", "applicantName", "nameOfApplicant"],
    gender: ["gender", "sex"]
  });

  const COUNTRY_ALIASES = Object.freeze({
    bangladesh: "BANGLADESH",
    bangladeshi: "BANGLADESH",
    bd: "BANGLADESH",
    india: "INDIA",
    indian: "INDIA",
    pakistan: "PAKISTAN",
    pakistani: "PAKISTAN",
    nepal: "NEPAL",
    nepalese: "NEPAL",
    "sri lanka": "SRI LANKA",
    "sri lankan": "SRI LANKA"
  });

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

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

  function normalizeKey(value = "") {
    return normalize(value).replace(/\s+/g, "");
  }

  function upperWords(value = "") {
    return compact(value)
      .replace(/[_]+/g, " ")
      .replace(/\s*-\s*/g, "-")
      .replace(/\s+/g, " ")
      .trim()
      .toUpperCase();
  }

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

  function displayDate(value = "") {
    if (global.FIVA?.StrictDobValidator?.normalizeDate) {
      return global.FIVA.StrictDobValidator.normalizeDate(value);
    }
    const parts = dateParts(value);
    if (!parts) return compact(value);
    return `${parts.day.padStart(2, "0")}/${parts.month.padStart(2, "0")}/${parts.year.padStart(4, "0")}`;
  }

  function sourceProfile(input = {}) {
    return input?.profile && typeof input.profile === "object" ? input.profile : input || {};
  }

  function lookupFor(input = {}) {
    const direct = sourceProfile(input);
    const lookup = new Map();
    Object.entries(direct || {}).forEach(([key, value]) => {
      if (key.startsWith("__")) return;
      lookup.set(String(key), value);
      lookup.set(normalizeKey(key), value);
    });
    return lookup;
  }

  function pick(input, aliases = []) {
    const lookup = lookupFor(input);
    for (const alias of aliases) {
      const raw = lookup.get(alias);
      if (compact(raw)) return compact(raw);
      const normalized = lookup.get(normalizeKey(alias));
      if (compact(normalized)) return compact(normalized);
    }
    return "";
  }

  function normalizeCountryValue(value = "") {
    const alias = global.FIVA?.NormalizeOptionText?.nationalityAliasResolver?.(value);
    if (alias) return alias;
    const source = normalize(value);
    if (!source) return "";
    const exact = COUNTRY_ALIASES[source];
    if (exact) return exact;
    const fuzzy = Object.entries(COUNTRY_ALIASES).find(([key]) => source.includes(key) || key.includes(source));
    return fuzzy?.[1] || upperWords(value);
  }

  function normalizeMissionValue(value = "", country = "") {
    const source = normalize(value);
    if (source && /dhaka/.test(source) && /bangladesh|mission|office|dhaka/.test(source)) return "BANGLADESH-DHAKA";
    if (source === "dhaka" && country === "BANGLADESH") return "BANGLADESH-DHAKA";
    return upperWords(value).replace(/^BANGLADESH DHAKA$/, "BANGLADESH-DHAKA");
  }

  function normalizeVisaType(value = "") {
    const source = normalize(value);
    if (!source) return "";
    if (/tourist|tourism|travel/.test(source)) return "e-Tourist Visa";
    if (/business/.test(source)) return "e-Business Visa";
    if (/medical/.test(source)) return "e-Medical Visa";
    return compact(value);
  }

  function normalizeGender(value = "") {
    const source = normalize(value);
    if (source === "f" || /\bfemale\b/.test(source)) return "Female";
    if (source === "m" || /\bmale\b/.test(source)) return "Male";
    return "";
  }

  function sourceConfidence(input = {}) {
    const source = sourceProfile(input);
    const existing = source.sourceConfidence && typeof source.sourceConfidence === "object"
      ? source.sourceConfidence
      : {};
    const meta = source.__fieldMeta || {};
    return Object.fromEntries(Object.entries(meta).map(([key, value]) => [key, {
      value: source[key] || "",
      confidence: Math.max(0, Math.min(1, Number(value?.confidence || 0) / 100)),
      source: value?.source || "unknown"
    }]).concat(Object.entries(existing)));
  }

  function defaultCountryFor(options = {}) {
    const site = String(options.siteUrl || "").toLowerCase();
    if (options.allowDefaultCountry === true && (options.defaultCountry === "BANGLADESH" || /indianvisa-bangladesh\.nic\.in/.test(site))) {
      return "BANGLADESH";
    }
    return "";
  }

  function normalizeProfile(input = {}, options = {}) {
    const source = sourceProfile(input);

    const countryRaw = pick(source, ALIASES.country);
    const country = normalizeCountryValue(countryRaw) || defaultCountryFor(options);
    const mission = normalizeMissionValue(pick(source, ALIASES.mission), country) || (country === "BANGLADESH" ? "BANGLADESH-DHAKA" : "");
    const nationalityRaw = pick(source, ALIASES.nationality);
    const nationality = normalizeCountryValue(nationalityRaw);
    const email = compact(pick(source, ALIASES.email)).toLowerCase();

    const profile = {
      fullName: compact(pick(source, ALIASES.fullName)),
      country,
      mission,
      nationality,
      dob: displayDate(pick(source, ALIASES.dob)),
      email,
      reEnterEmail: compact(pick(source, ALIASES.reEnterEmail)).toLowerCase() || email,
      arrivalDate: displayDate(pick(source, ALIASES.expectedArrival)),
      expectedArrival: displayDate(pick(source, ALIASES.expectedArrival)),
      visaType: normalizeVisaType(pick(source, ALIASES.visaType)),
      purpose: compact(pick(source, ALIASES.purpose)),
      surname: compact(pick(source, ALIASES.surname)),
      givenName: compact(pick(source, ALIASES.givenName)),
      passportNumber: compact(pick(source, ALIASES.passportNumber)).toUpperCase().replace(/[^A-Z0-9]/g, ""),
      passportIssueDate: displayDate(pick(source, ALIASES.passportIssueDate)),
      passportExpiryDate: displayDate(pick(source, ALIASES.passportExpiryDate)),
      gender: normalizeGender(pick(source, ALIASES.gender)),
      sourceConfidence: sourceConfidence(source)
    };

    return Object.fromEntries(STANDARD_KEYS.map((key) => [key, profile[key] || ""]));
  }

  function toQueueProfile(input = {}, options = {}) {
    const source = sourceProfile(input);
    const standard = normalizeProfile(source, options);
    const queue = {
      country: standard.country,
      mission: standard.mission,
      nationality: standard.nationality,
      dateOfBirth: standard.dob,
      dob: standard.dob,
      email: standard.email,
      reEnterEmail: standard.reEnterEmail,
      expectedArrivalDate: standard.arrivalDate || standard.expectedArrival,
      expectedArrival: standard.expectedArrival,
      visaType: standard.visaType,
      purpose: standard.purpose,
      surname: standard.surname,
      givenNames: standard.givenName,
      givenName: standard.givenName,
      passportNumber: standard.passportNumber,
      passportIssueDate: standard.passportIssueDate,
      passportExpiryDate: standard.passportExpiryDate,
      fullName: standard.fullName || compact(source.fullName),
      gender: standard.gender || compact(source.gender),
      cityOfBirth: compact(source.cityOfBirth),
      countryOfBirth: normalizeCountryValue(source.countryOfBirth),
      religion: compact(source.religion),
      education: compact(source.education)
    };

    return Object.fromEntries(Object.entries(queue).filter(([, value]) => compact(value)));
  }

  const ProfileNormalizer = Object.freeze({
    ALIASES,
    STANDARD_KEYS,
    compact,
    displayDate,
    normalize,
    normalizeCountryValue,
    defaultCountryFor,
    normalizeGender,
    normalizeMissionValue,
    normalizeProfile,
    sourceConfidence,
    toQueueProfile
  });

  global.FIVA = Object.assign(global.FIVA || {}, { ProfileNormalizer });

  if (typeof module !== "undefined" && module.exports) {
    module.exports = ProfileNormalizer;
  }
})(typeof globalThis !== "undefined" ? globalThis : this);
