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

  const REQUIRED_FIELDS = Object.freeze([
    "fullName",
    "passportNumber",
    "nationality",
    "country",
    "dateOfBirth",
    "gender"
  ]);

  const FIELD_LABELS = Object.freeze({
    fullName: "Full Name",
    surname: "Surname",
    givenNames: "Given Names",
    passportNumber: "Passport Number",
    nationality: "Nationality",
    country: "Country",
    mission: "Mission",
    dateOfBirth: "Date of Birth",
    gender: "Gender",
    email: "Email",
    reEnterEmail: "Re-enter Email",
    expectedArrivalDate: "Expected Arrival Date",
    visaType: "Visa Type",
    purpose: "Purpose",
    cityOfBirth: "City of Birth",
    countryOfBirth: "Country of Birth",
    religion: "Religion",
    education: "Education",
    passportIssueDate: "Passport Issue Date",
    passportExpiryDate: "Passport Expiry Date"
  });

  const HIGH_CONFIDENCE = 90;

  const COUNTRY_NATIONALITY = Object.freeze({
    bangladesh: { country: "Bangladesh", nationality: "Bangladeshi" },
    bangladeshi: { country: "Bangladesh", nationality: "Bangladeshi" },
    india: { country: "India", nationality: "Indian" },
    indian: { country: "India", nationality: "Indian" },
    pakistan: { country: "Pakistan", nationality: "Pakistani" },
    pakistani: { country: "Pakistan", nationality: "Pakistani" },
    nepal: { country: "Nepal", nationality: "Nepalese" },
    nepalese: { country: "Nepal", nationality: "Nepalese" },
    "sri lanka": { country: "Sri Lanka", nationality: "Sri Lankan" },
    "sri lankan": { country: "Sri Lanka", nationality: "Sri Lankan" },
    "united states": { country: "United States", nationality: "American" },
    usa: { country: "United States", nationality: "American" },
    american: { country: "United States", nationality: "American" },
    "united kingdom": { country: "United Kingdom", nationality: "British" },
    uk: { country: "United Kingdom", nationality: "British" },
    british: { country: "United Kingdom", nationality: "British" },
    canada: { country: "Canada", nationality: "Canadian" },
    canadian: { country: "Canada", nationality: "Canadian" },
    australia: { country: "Australia", nationality: "Australian" },
    australian: { country: "Australia", nationality: "Australian" }
  });

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

  function normalize(value = "") {
    return compact(value).toLowerCase();
  }

  function splitFullName(value = "") {
    const parts = compact(value).split(" ").filter(Boolean);
    if (parts.length < 2) return { givenNames: compact(value), surname: "" };
    return {
      givenNames: parts.slice(0, -1).join(" "),
      surname: parts.slice(-1).join("")
    };
  }

  function validateProfile(profile = {}, source = {}) {
    const validators = global.FIVA?.Validators;
    if (!validators?.validateField) return profile;
    return Object.fromEntries(Object.entries(profile).filter(([key, value]) => (
      validators.validateField(key, value, source).ok
    )));
  }

  function normalizeProfile(fields = {}, source = {}) {
    const profile = {};

    Object.keys(FIELD_LABELS).forEach((key) => {
      const value = compact(fields[key]);
      if (value) profile[key] = value;
    });

    if (!profile.dateOfBirth && fields.dob) profile.dateOfBirth = compact(fields.dob);
    if (!profile.expectedArrivalDate && fields.arrivalDate) profile.expectedArrivalDate = compact(fields.arrivalDate);
    if (!profile.givenNames && fields.givenName) profile.givenNames = compact(fields.givenName);

    if (!profile.fullName) {
      profile.fullName = [profile.givenNames, profile.surname].filter(Boolean).join(" ");
    }

    if (profile.email && !profile.reEnterEmail) {
      profile.reEnterEmail = profile.email;
    }

    if (profile.fullName && (!profile.givenNames || !profile.surname)) {
      const split = splitFullName(profile.fullName);
      if (!profile.givenNames && split.givenNames) profile.givenNames = split.givenNames;
      if (!profile.surname && split.surname) profile.surname = split.surname;
    }

    return validateProfile(Object.fromEntries(Object.entries(profile).filter(([, value]) => Boolean(value))), source);
  }

  function normalizeMeta(meta = {}) {
    return Object.fromEntries(Object.entries(meta || {}).map(([key, value]) => [key, {
      confidence: Math.max(0, Math.min(100, Number(value?.confidence || 0))),
      source: value?.source || "unknown",
      verified: value?.verified === true
    }]));
  }

  function buildFieldRecords(profile = {}, meta = {}, source = {}) {
    const normalizedMeta = normalizeMeta(meta);
    const sourceConfidence = Math.max(0, Math.min(100, Number(source.confidence || 0)));
    return Object.entries(FIELD_LABELS).map(([key, label]) => {
      const rawConfidence = normalizedMeta[key]?.confidence || (profile[key] ? sourceConfidence : 0);
      const recordSource = normalizedMeta[key]?.source || source.type || "unknown";
      const confidence = source.type === "image" && recordSource === "text"
        ? Math.min(rawConfidence, sourceConfidence || rawConfidence)
        : rawConfidence;
      return {
        key,
        label,
        value: profile[key] || "",
        required: REQUIRED_FIELDS.includes(key),
        present: Boolean(profile[key]),
        confidence,
        source: recordSource,
        verified: normalizedMeta[key]?.verified === true,
        requiresReview: REQUIRED_FIELDS.includes(key)
          && Boolean(profile[key])
          && !(normalizedMeta[key]?.verified === true)
          && confidence < HIGH_CONFIDENCE
      };
    });
  }

  function calculateConfidence(profile = {}, source = {}, meta = {}) {
    const requiredScore = REQUIRED_FIELDS.filter((key) => profile[key]).length / REQUIRED_FIELDS.length;
    const optionalFields = ["email", "reEnterEmail", "expectedArrivalDate", "visaType", "purpose", "passportIssueDate", "passportExpiryDate", "mission"];
    const optionalScore = optionalFields.filter((key) => profile[key]).length / optionalFields.length;
    const sourceConfidence = Math.max(0, Math.min(100, Number(source.confidence || 0))) / 100;
    const fieldConfidences = REQUIRED_FIELDS
      .map((key) => Number(meta[key]?.confidence || 0))
      .filter(Boolean);
    const fieldConfidence = fieldConfidences.length
      ? fieldConfidences.reduce((total, value) => total + value, 0) / (fieldConfidences.length * 100)
      : sourceConfidence;
    return Math.round(((requiredScore * 0.58) + (optionalScore * 0.14) + (sourceConfidence * 0.12) + (fieldConfidence * 0.16)) * 100);
  }

  function map(fields = {}, source = {}) {
    const meta = normalizeMeta(fields.__fieldMeta || fields.__meta || {});
    const profile = normalizeProfile(fields, source);
    const missing = REQUIRED_FIELDS.filter((key) => !profile[key]);
    const records = buildFieldRecords(profile, meta, source);
    const review = records.filter((record) => record.requiresReview).map((record) => record.key);
    const confidence = calculateConfidence(profile, source, meta);
    const status = "Ready";

    console.log("[FIVA]", "Field mapping complete");
    console.log("[FIVA]", `Extraction confidence: ${confidence}%`);
    return {
      profile,
      fields: records,
      missing,
      review,
      confidence,
      status,
      source: {
        type: source.type || "unknown",
        fileName: source.fileName || "",
        textLength: Number(source.textLength || 0),
        confidence: Number(source.confidence || 0)
      },
      updatedAt: new Date().toISOString()
    };
  }

  function updateFromRecords(records = [], current = {}) {
    const next = { ...current };
    records.forEach((record) => {
      if (!record?.key) return;
      next[record.key] = compact(record.value);
    });
    return normalizeProfile(next);
  }

  function metaFromRecords(records = []) {
    return Object.fromEntries((records || []).filter((record) => record?.key).map((record) => [record.key, {
      confidence: Number(record.confidence || 0),
      source: record.source || "manual",
      verified: record.verified === true
    }]));
  }

  function autofillGate(analysis = {}) {
    const hasData = Object.values(analysis.profile || {}).some(Boolean);
    if (!hasData) {
      return {
        ok: false,
        message: "FIVA document is not ready."
      };
    }

    return { ok: true, message: "Ready" };
  }

  const FieldMapper = Object.freeze({
    COUNTRY_NATIONALITY,
    FIELD_LABELS,
    REQUIRED_FIELDS,
    autofillGate,
    buildFieldRecords,
    map,
    metaFromRecords,
    normalizeProfile,
    updateFromRecords
  });

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