/*
 * Cleaned loader for the OzLiveness plugin entry.
 * Responsibilities:
 * - Resolve the current script directory.
 * - Load `ozliveness_core.clean.js`.
 * - Queue public API calls until the core singleton is ready.
 * - Preload configured language bundles.
 */
((inputConfig) => {
  "use strict";

  const config = inputConfig || {};

  const globalObject =
    typeof globalThis !== "undefined"
      ? globalThis
      : typeof window !== "undefined"
        ? window
        : typeof self !== "undefined"
          ? self
          : {};
  const documentRef = globalObject.document;
  const VERSION = "1.8.1-10";
  const CORE_FILE = "ozliveness_core.clean.js";
  const ASYNC_METHODS = new Set([
    "open",
    "close",
    "add_lang",
    "set_lang",
    "hide",
    "check_license"
  ]);

  const pendingCalls = [];
  const languages = Array.isArray(config.la) && config.la.length ? [...config.la] : ["en"];

  let api = null;
  let isLoaded = false;

  function getCurrentScript() {
    if (!documentRef) return null;
    if (documentRef.currentScript) return documentRef.currentScript;

    const scripts = documentRef.getElementsByTagName
      ? documentRef.getElementsByTagName("script")
      : [];
    return scripts.length ? scripts[scripts.length - 1] : null;
  }

  function getBaseDir(scriptElement) {
    if (scriptElement && scriptElement.src) {
      const url = new URL(scriptElement.src, globalObject.location?.href || "http://localhost/");
      return new URL(".", url).toString().replace(/\/$/, "");
    }

    if (globalObject.location?.href) {
      return new URL(".", globalObject.location.href).toString().replace(/\/$/, "");
    }

    return "";
  }

  function withVersion(urlString) {
    const url = new URL(urlString, globalObject.location?.href || "http://localhost/");
    url.searchParams.set("ver", VERSION);
    return url.toString();
  }

  function resolveAssetUrls(baseDir, fileName) {
    const candidates = [];
    if (baseDir) {
      candidates.push(withVersion(`${baseDir}/${fileName}`));
      if (!baseDir.endsWith("/plugin")) {
        candidates.push(withVersion(`${baseDir}/plugin/${fileName}`));
      }
    } else {
      candidates.push(withVersion(fileName));
      candidates.push(withVersion(`plugin/${fileName}`));
    }
    return [...new Set(candidates)];
  }

  function loadScript(url, { async = true } = {}) {
    return new Promise((resolve, reject) => {
      if (!documentRef || !documentRef.createElement || !documentRef.head?.appendChild) {
        reject(new Error("document is not available"));
        return;
      }

      const script = documentRef.createElement("script");
      script.src = url;
      script.type = "text/javascript";
      script.async = async;
      script.onload = () => resolve();
      script.onerror = error => reject(error instanceof Error ? error : new Error(String(error)));
      documentRef.head.appendChild(script);
    });
  }

  async function loadFirstAvailable(urls, options) {
    let lastError = null;

    for (const url of urls) {
      try {
        await loadScript(url, options);
        return url;
      } catch (error) {
        lastError = error;
      }
    }

    throw lastError || new Error("Failed to load script");
  }

  function rejectPending(errorValue) {
    const errorObject = {
      code: String(errorValue),
      err: errorValue,
      toString() {
        return String(errorValue);
      }
    };

    pendingCalls.splice(0).forEach(call => {
      try {
        call.reject(errorObject);
      } catch {}
    });
  }

  function flushPending() {
    const queued = pendingCalls.splice(0);

    queued.forEach(call => {
      try {
        if (api && typeof api[call.method] === "function") {
          call.resolve(api[call.method](...call.args));
          return;
        }

        call.reject(new Error(`Method ${call.method} not found`));
      } catch (error) {
        call.reject(error);
      }
    });
  }

  function queueLanguageRegistration() {
    languages.forEach(language => {
      try {
        globalObject.OzLiveness.add_lang(language, {});
      } catch {}
    });
  }

  function preloadLanguageBundles(baseDir) {
    languages.forEach(language => {
      const urls = resolveAssetUrls(baseDir, `add_lang/${language}.js`);
      loadFirstAvailable(urls, { async: true }).catch(() => {});
    });
  }

  function createBridge() {
    return new Proxy(
      {},
      {
        get(_target, property) {
          if (property === "get_langs") {
            return () => languages;
          }

          if (property === "version") {
            return VERSION;
          }

          if (typeof property === "string" && ASYNC_METHODS.has(property)) {
            return (...args) =>
              new Promise((resolve, reject) => {
                if (isLoaded && api && typeof api[property] === "function") {
                  try {
                    resolve(api[property](...args));
                  } catch (error) {
                    reject(error);
                  }
                  return;
                }

                pendingCalls.push({
                  method: property,
                  args,
                  resolve,
                  reject
                });
              });
          }

          if (isLoaded && api) {
            return api[property];
          }

          return undefined;
        },
        set(_target, property, value) {
          if (isLoaded && api) {
            api[property] = value;
          }
          return true;
        }
      }
    );
  }

  const currentScript = getCurrentScript();
  const baseDir = getBaseDir(currentScript);
  const bridge = createBridge();

  globalObject.OzLiveness = bridge;
  queueLanguageRegistration();

  loadFirstAvailable(resolveAssetUrls(baseDir, CORE_FILE), { async: false })
    .then(() => {
      if (!globalObject.OzLiveness || typeof globalObject.OzLiveness !== "object") {
        rejectPending("422");
        return;
      }

      api = globalObject.OzLiveness;
      isLoaded = true;
      flushPending();
      preloadLanguageBundles(baseDir);
    })
    .catch(error => {
      rejectPending(error);
    });
})({
  p: "=hDFI09ewr=",
  la: ["en", "es", "kz", "pt-br", "ru"]
});
