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

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

  function config() {
    return global.FIVA?.RuntimeConfig || {
      dropdownRetryCount: 3,
      fieldTimeoutMs: 8000,
      stabilizationDelayMinMs: 800,
      stabilizationDelayMaxMs: 1500,
      dropdownQuietMs: 500,
      fastActionDelayMs: 120
    };
  }

  function smart() {
    return global.FIVA?.SelectSmartOption || null;
  }

  const PLACEHOLDER_PATTERN = /\b(select|choose|loading|wait|please wait|please select|none)\b/i;
  const LOADING_PATTERN = /\b(loading|wait|please wait)\b/i;

  function optionNormalizer() {
    return global.FIVA?.NormalizeOptionText || null;
  }

  function wait(ms = 80, signal) {
    if (signal?.aborted) return Promise.resolve(false);
    return new Promise((resolve) => {
      const timer = setTimeout(() => {
        signal?.removeEventListener?.("abort", onAbort);
        resolve(true);
      }, ms);
      function onAbort() {
        clearTimeout(timer);
        resolve(false);
      }
      signal?.addEventListener?.("abort", onAbort, { once: true });
    });
  }

  function humanDelay(min = config().stabilizationDelayMinMs, max = config().stabilizationDelayMaxMs, signal) {
    const duration = Math.floor(Number(min) + (Math.random() * Math.max(1, Number(max) - Number(min))));
    return wait(duration, signal);
  }

  function labelFor(fieldKey = "") {
    return String(fieldKey || "dropdown")
      .replace(/([A-Z])/g, " $1")
      .replace(/^./, (letter) => letter.toUpperCase())
      .trim();
  }

  function normalize(value = "") {
    const normalizer = optionNormalizer();
    if (normalizer?.normalizeOptionText) return normalizer.normalizeOptionText(value);
    return String(value || "")
      .trim()
      .toUpperCase()
      .replace(/[_-]+/g, " ")
      .replace(/\s+/g, " ")
      .trim();
  }

  function compactMatch(value = "") {
    const normalizer = optionNormalizer();
    if (normalizer?.compactOptionText) return normalizer.compactOptionText(value);
    return normalize(value).replace(/\s+/g, "");
  }

  function optionText(option) {
    const normalizer = optionNormalizer();
    if (normalizer?.optionText) return normalizer.optionText(option);
    return String(option?.text || option?.textContent || option?.label || option?.innerText || "").replace(/\s+/g, " ").trim();
  }

  function optionValue(option) {
    const normalizer = optionNormalizer();
    if (normalizer?.optionValue) return normalizer.optionValue(option);
    return String(option?.value || "").replace(/\s+/g, " ").trim();
  }

  function isPlaceholderOption(option) {
    const normalizer = optionNormalizer();
    if (normalizer?.isPlaceholderOption) return normalizer.isPlaceholderOption(option);
    const text = optionText(option);
    const value = optionValue(option);
    if (!value && !text) return true;
    return PLACEHOLDER_PATTERN.test(text) || (!text && PLACEHOLDER_PATTERN.test(value));
  }

  function validOptions(select) {
    const smartOptions = smart()?.validOptions?.(select);
    const list = Array.isArray(smartOptions) ? smartOptions : Array.from(select?.options || []);
    return list.filter((option) => !isPlaceholderOption(option));
  }

  function availableOptionLabels(select) {
    return Array.from(select?.options || [])
      .map((option) => optionText(option) || optionValue(option))
      .filter(Boolean);
  }

  function snapshot(select) {
    if (!select) return {
      html: "",
      count: 0,
      disabled: true,
      signature: ""
    };
    return {
      html: select.innerHTML || "",
      count: select.options?.length || 0,
      disabled: select.disabled === true,
      signature: availableOptionLabels(select).join("|")
    };
  }

  function hasSnapshotChanged(select, before) {
    if (!select) return false;
    const current = snapshot(select);
    return current.html !== before.html
      || current.count !== before.count
      || current.disabled !== before.disabled
      || current.signature !== before.signature;
  }

  function trace(options = {}, message, level = "info") {
    if (typeof options.onTrace === "function") options.onTrace(message, level);
  }

  function candidatesFor(fieldKey = "", value = "") {
    const base = smart()?.candidatesFor?.(fieldKey, value) || [normalize(value)];
    const candidates = new Set(base.map(normalize));
    const source = normalize(value);
    if (fieldKey === "country" && /BANGLADESH|BD|BANGLADESHI/.test(source)) {
      candidates.add("BANGLADESH");
      candidates.add("BD");
    }
    if (fieldKey === "mission" && /DHAKA|BANGLADESH/.test(source)) {
      candidates.add("DHAKA");
      candidates.add("BANGLADESH DHAKA");
      candidates.add("BANGLADESHDHAKA");
      candidates.add("BANGLADESH-DHAKA");
    }
    if (fieldKey === "nationality" && /BANGLADESH|BANGLADESHI/.test(source)) {
      candidates.add("BANGLADESH");
      candidates.add("BANGLADESHI");
    }
    return Array.from(candidates).filter(Boolean);
  }

  function levenshteinRatio(left = "", right = "") {
    if (!left || !right) return 0;
    const a = String(left).slice(0, 48);
    const b = String(right).slice(0, 48);
    const rows = Array.from({ length: a.length + 1 }, () => []);
    for (let i = 0; i <= a.length; i += 1) rows[i][0] = i;
    for (let j = 0; j <= b.length; j += 1) rows[0][j] = j;
    for (let i = 1; i <= a.length; i += 1) {
      for (let j = 1; j <= b.length; j += 1) {
        rows[i][j] = Math.min(
          rows[i - 1][j] + 1,
          rows[i][j - 1] + 1,
          rows[i - 1][j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1)
        );
      }
    }
    return 1 - (rows[a.length][b.length] / Math.max(a.length, b.length));
  }

  function matchOption(select, options = {}) {
    const smartMatch = smart()?.matchOption?.(select, options);
    if (smartMatch?.option) return smartMatch;

    const fieldKey = options.fieldKey || "";
    const candidates = candidatesFor(fieldKey, options.value || "");
    const list = validOptions(select);
    const strategies = [
      ["exact_value", (option, candidate) => normalize(optionValue(option)) === normalize(candidate)],
      ["exact_text", (option, candidate) => normalize(optionText(option)) === normalize(candidate)],
      ["normalized_exact", (option, candidate) => compactMatch(optionValue(option)) === compactMatch(candidate) || compactMatch(optionText(option)) === compactMatch(candidate)],
      ["contains", (option, candidate) => {
        const normalizer = optionNormalizer();
        if (normalizer?.matchesOptionValue?.(option, candidate)) return true;
        const needle = compactMatch(candidate);
        const text = compactMatch(optionText(option));
        const value = compactMatch(optionValue(option));
        const parts = [text, value].filter((part) => part.length >= 2);
        return needle.length >= 2 && (
          parts.some((part) => part.includes(needle))
          || parts.some((part) => needle.includes(part))
        );
      }],
      ["fuzzy_similarity", (option, candidate) => {
        return levenshteinRatio(compactMatch(candidate), compactMatch(optionText(option))) > 0.72
          || levenshteinRatio(compactMatch(candidate), compactMatch(optionValue(option))) > 0.72;
      }]
    ];

    for (const [strategy, matcher] of strategies) {
      for (const candidate of candidates) {
        const option = list.find((item) => matcher(item, candidate));
        if (option) return { option, strategy, candidates, optionCount: list.length };
      }
    }

    return { option: null, strategy: "", candidates, optionCount: list.length };
  }

  function fireMouse(select, type) {
    select.dispatchEvent(new MouseEvent(type, {
      bubbles: true,
      cancelable: true,
      view: global
    }));
  }

  function fireEvent(select, type) {
    select.dispatchEvent(new Event(type, { bubbles: true, cancelable: true }));
  }

  async function humanOpen(select, options = {}) {
    select.scrollIntoView({ block: "center", inline: "nearest" });
    fireMouse(select, "mouseenter");
    fireMouse(select, "mousemove");
    fireMouse(select, "mousedown");
    select.focus({ preventScroll: true });
    select.click();
    await wait(config().fastActionDelayMs || 120, options.signal);
  }

  async function applyHumanSelection(select, option, options = {}) {
    if (!select || !option || options.signal?.aborted) return false;
    await humanOpen(select, options);
    if (options.signal?.aborted) return false;
    select.selectedIndex = option.index;
    option.selected = true;
    if (optionValue(option)) select.value = option.value;
    fireEvent(select, "input");
    fireEvent(select, "change");
    select.blur();
    fireEvent(select, "blur");
    return true;
  }

  function verifySelection(select, option, options = {}) {
    if (!select || !option) return false;
    const selected = select.options[select.selectedIndex];
    if (!selected || select.selectedIndex <= 0) return false;
    const target = options.value || "";
    const normalizer = optionNormalizer();
    if (target && normalizer?.matchesOptionValue && !normalizer.matchesOptionValue(selected, target)) return false;
    if (selected === option || optionValue(selected) === optionValue(option)) return true;
    const matched = matchOption(select, options);
    return Boolean(matched.option && (selected === matched.option || optionValue(selected) === optionValue(matched.option)));
  }

  async function waitForDropdownReady(select, options = {}) {
    const timeout = Math.max(400, Math.min(Number(options.timeout || config().fieldTimeoutMs || 8000), config().fieldTimeoutMs || 8000));
    const quiet = Math.max(160, Number(options.quiet || config().dropdownQuietMs || 500));
    const startedAt = Date.now();
    const signal = options.signal;
    let stableSince = Date.now();
    let lastSignature = snapshot(select).signature;
    let lastDisabled = select?.disabled === true;

    const observer = typeof MutationObserver !== "undefined" && select
      ? new MutationObserver(() => {
        stableSince = Date.now();
        lastSignature = snapshot(select).signature;
        lastDisabled = select.disabled === true;
      })
      : null;
    observer?.observe(select, { childList: true, subtree: true, attributes: true });

    try {
      while (Date.now() - startedAt < timeout) {
        if (signal?.aborted) return { ready: false, reason: "stopped_manually", count: 0 };
        if (!select) return { ready: false, reason: "selector_missing", count: 0 };

        const current = snapshot(select);
        if (current.signature !== lastSignature || current.disabled !== lastDisabled) {
          lastSignature = current.signature;
          lastDisabled = current.disabled;
          stableSince = Date.now();
        }

        const optionsList = validOptions(select);
        const loading = Array.from(select.options || []).some((option) => LOADING_PATTERN.test(optionText(option)) || LOADING_PATTERN.test(optionValue(option)));
        if (!select.disabled && !loading && optionsList.length > 0 && Date.now() - stableSince >= quiet) {
          return { ready: true, reason: "", count: optionsList.length };
        }

        await wait(120, signal);
      }
      return { ready: false, reason: validOptions(select).length ? "verification_failed" : "dropdown_not_loaded", count: validOptions(select).length };
    } finally {
      observer?.disconnect();
    }
  }

  async function waitForDropdownPopulation(selectOrResolver, before = null, options = {}) {
    const timeout = Math.max(800, Math.min(Number(options.timeout || config().asyncDependencyTimeoutMs || 8000), config().asyncDependencyTimeoutMs || 8000));
    const quiet = Math.max(300, Number(options.quiet || config().dropdownQuietMs || 500));
    const startedAt = Date.now();
    const signal = options.signal;
    let stableSince = Date.now();
    let lastSignature = "";
    let lastCount = -1;

    function resolveSelect() {
      return typeof selectOrResolver === "function" ? selectOrResolver() : selectOrResolver;
    }

    while (Date.now() - startedAt < timeout) {
      if (signal?.aborted) return { ready: false, reason: "stopped_manually", count: 0, select: null };
      const select = resolveSelect();
      if (!select || !select.isConnected) {
        stableSince = Date.now();
        await wait(120, signal);
        continue;
      }

      const current = snapshot(select);
      const changed = before ? hasSnapshotChanged(select, before) : true;
      const optionsList = validOptions(select);
      const loading = Array.from(select.options || []).some((option) => LOADING_PATTERN.test(optionText(option)) || LOADING_PATTERN.test(optionValue(option)));
      const signature = current.signature;

      if (signature !== lastSignature || optionsList.length !== lastCount || select.disabled) {
        lastSignature = signature;
        lastCount = optionsList.length;
        stableSince = Date.now();
      }

      if (changed && !select.disabled && !loading && optionsList.length > 0 && Date.now() - stableSince >= quiet) {
        return { ready: true, reason: "", count: optionsList.length, select };
      }

      await wait(120, signal);
    }

    const finalSelect = resolveSelect();
    return {
      ready: false,
      reason: validOptions(finalSelect).length ? "verification_failed" : "dropdown_not_loaded",
      count: validOptions(finalSelect).length,
      select: finalSelect || null
    };
  }

  async function waitForDependentDropdown(dependentSelect, before, options = {}) {
    const resolver = typeof options.getDependentSelect === "function" ? options.getDependentSelect : () => dependentSelect;
    const requiresDependency = Boolean(options.dependentFieldKey);
    if (!resolver() && !requiresDependency) return { refreshed: true, reason: "no_dependent_select" };
    trace(options, "Waiting ASP.NET update");
    const populated = await waitForDropdownPopulation(resolver, before, options);
    if (populated.ready) {
      trace(options, `${labelFor(options.dependentFieldKey)} dropdown refreshed`);
      return { refreshed: true, reason: "", select: populated.select };
    }
    return { refreshed: false, reason: populated.reason || "dependency_not_completed", select: populated.select };
  }

  async function choose(select, options = {}) {
    const fieldKey = options.fieldKey || "";
    const fieldLabel = labelFor(fieldKey);
    const attempts = Math.max(1, Math.min(Number(options.attempts || config().dropdownRetryCount || 3), config().dropdownRetryCount || 3));
    const timeout = Math.max(400, Math.min(Number(options.timeout || config().fieldTimeoutMs || 8000), config().fieldTimeoutMs || 8000));
    const startedAt = Date.now();
    let lastReason = "option_not_found";

    const resolveSelect = typeof options.resolveSelect === "function" ? options.resolveSelect : () => select;
    console.log("[FIVA]", `available ${fieldKey || "dropdown"} options:`, availableOptionLabels(resolveSelect()));

    for (let attempt = 0; attempt < attempts; attempt += 1) {
      if (options.signal?.aborted) return { success: false, reason: "stopped_manually", attempts: attempt };
      const remaining = timeout - (Date.now() - startedAt);
      if (remaining <= 0) break;
      const activeSelect = resolveSelect();
      if (!activeSelect || !activeSelect.isConnected) {
        lastReason = activeSelect ? "stale_dom_reference" : "selector_missing";
        await wait(160, options.signal);
        continue;
      }

      trace(options, `${fieldLabel} dropdown opened`);
      const ready = await waitForDropdownReady(activeSelect, {
        ...options,
        timeout: remaining,
        quiet: config().dropdownQuietMs || 500
      });
      if (!ready.ready) {
        lastReason = ready.reason || "dropdown_not_loaded";
        break;
      }

      const freshSelect = resolveSelect() || activeSelect;
      if (!freshSelect.isConnected) {
        lastReason = "stale_dom_reference";
        await wait(180, options.signal);
        continue;
      }

      console.log("[FIVA]", `available ${fieldKey || "dropdown"} options:`, availableOptionLabels(freshSelect));
      const matched = matchOption(freshSelect, options);
      if (!matched.option && fieldKey === "mission") {
        const dhakaOption = validOptions(freshSelect).find((option) => /DHAKA/i.test(`${optionText(option)} ${optionValue(option)}`));
        if (dhakaOption) matched.option = dhakaOption;
      }
      if (!matched.option) {
        lastReason = "option_not_found";
        trace(options, `${fieldLabel} option not found`, "warn");
        await wait(180, options.signal);
        continue;
      }

      const dependentSelect = typeof options.getDependentSelect === "function" ? options.getDependentSelect() : null;
      const dependentBefore = snapshot(dependentSelect);
      trace(options, `${fieldLabel} option matched: ${optionText(matched.option) || optionValue(matched.option)}`);
      await applyHumanSelection(freshSelect, matched.option, options);
      const verifiedSelect = resolveSelect() || freshSelect;
      if (!verifiedSelect.isConnected) {
        lastReason = "stale_dom_reference";
        trace(options, `${fieldLabel} dropdown was refreshed after selection`, "warn");
        await wait(220, options.signal);
        continue;
      }

      const verified = typeof options.verify === "function"
        ? options.verify(verifiedSelect, matched.option)
        : verifySelection(verifiedSelect, matched.option, options);
      if (!verified || !verifySelection(verifiedSelect, matched.option, options)) {
        lastReason = "verification_failed";
        trace(options, `${fieldLabel} verification failed`, "warn");
        trace(options, "Normalized option mismatch", "warn");
        trace(options, `Retrying ${fieldLabel.toLowerCase()} selection`, "warn");
        await wait(220, options.signal);
        continue;
      }

      trace(options, `${fieldLabel} selected successfully`);
      trace(options, `${fieldLabel} verification passed`);
      if (dependentSelect || options.dependentFieldKey) {
        const refresh = await waitForDependentDropdown(dependentSelect, dependentBefore, {
          ...options,
          getDependentSelect: options.getDependentSelect,
          timeout: Math.min(config().asyncDependencyTimeoutMs || 8000, Math.max(1200, timeout - (Date.now() - startedAt)))
        });
        if (!refresh.refreshed) {
          lastReason = refresh.reason || "dependency_not_completed";
          trace(options, `${labelFor(options.dependentFieldKey)} dropdown refresh not detected`, "warn");
          if (options.dependentFieldKey) continue;
        }
      }

      await humanDelay(config().stabilizationDelayMinMs || 800, config().stabilizationDelayMaxMs || 1500, options.signal);
      return {
        success: true,
        reason: "",
        option: matched.option,
        strategy: matched.strategy,
        attempts: attempt + 1,
        optionCount: matched.optionCount,
        selectedText: optionText(matched.option),
        selectedValue: optionValue(matched.option)
      };
    }

    console.log("[FIVA]", `available ${fieldKey || "dropdown"} options:`, availableOptionLabels(resolveSelect()));
    return {
      success: false,
      reason: lastReason,
      attempts,
      optionCount: validOptions(select).length
    };
  }

  const HumanDropdownSelect = Object.freeze({
    applyHumanSelection,
    availableOptionLabels,
    choose,
    compactMatch,
    humanDelay,
    humanOpen,
    isPlaceholderOption,
    levenshteinRatio,
    matchOption,
    normalize,
    snapshot,
    validOptions,
    verifySelection,
    waitForDependentDropdown,
    waitForDependentDropdownRefresh: waitForDependentDropdown,
    waitForDropdownPopulation,
    waitForDropdownReady
  });

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

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