const UTMParams = [
  'utm_id',
  'utm_source',
  'utm_medium',
  'utm_campaign',
  'utm_content',
  'utm_term',
];

const Avoma = {};
const SENTRY_EVENT_SOURCE = 'avoma-sdk';
const SENTRY_FEATURE = 'scheduler_router';
const ROUTER_DIAGNOSTICS_VERSION = 'router-handoff-v2';
const SDK_SENTRY_SAFE_TAG_KEYS = new Set([
  'diagnostics_version',
  'feature',
  'form_id',
  'handoff_id',
  'handoff_result',
  'page_host',
  'router_id',
  'section',
  'source',
  'submission_source',
]);
const SDK_SENTRY_SAFE_EXTRA_KEYS = new Set([
  'diagnosticsVersion',
  'documentVisibility',
  'elapsedMs',
  'formId',
  'handoffResult',
  'hasContentWindow',
  'hasMktoForms2',
  'hasPendingMessage',
  'hasRouterReadyTimeout',
  'hasSubmissionValues',
  'iframeAgeMs',
  'iframeLoaded',
  'iframeRetryCount',
  'iframeRouterReady',
  'iframeSrc',
  'iframeVisibility',
  'loadRetryCount',
  'modalVisibility',
  'pageHost',
  'pendingMessagePosted',
  'registeredRouterCount',
  'registrationSource',
  'retryReason',
  'routerId',
  'routerMessageId',
  'submissionSource',
  'waitMs',
]);
const SDK_SENTRY_SAFE_LEVELS = new Set([
  'debug',
  'error',
  'fatal',
  'info',
  'log',
  'warning',
]);
const SDK_SENTRY_SAFE_BOOLEAN_EXTRA_KEYS = new Set([
  'hasContentWindow',
  'hasMktoForms2',
  'hasPendingMessage',
  'hasRouterReadyTimeout',
  'hasSubmissionValues',
  'pendingMessagePosted',
]);
const SDK_SENTRY_SAFE_NUMBER_EXTRA_KEYS = new Set([
  'elapsedMs',
  'iframeAgeMs',
  'iframeRetryCount',
  'loadRetryCount',
  'registeredRouterCount',
  'waitMs',
]);
const SDK_SENTRY_SAFE_IDENTIFIER_EXTRA_KEYS = new Set([
  'formId',
  'routerId',
  'routerMessageId',
]);
const SDK_SENTRY_SAFE_EXTRA_ENUM_VALUES = {
  diagnosticsVersion: new Set([ROUTER_DIAGNOSTICS_VERSION]),
  documentVisibility: new Set(['hidden', 'prerender', 'visible']),
  handoffResult: new Set(['ack_timeout', 'acknowledged', 'started']),
  iframeLoaded: new Set(['false', 'true']),
  iframeRouterReady: new Set(['false', 'true']),
  iframeVisibility: new Set(['hidden', 'visible']),
  modalVisibility: new Set(['hidden', 'visible']),
  registrationSource: new Set(['initRouter', 'setUserDetails']),
  retryReason: new Set([
    'loadTimeout',
    'routerReadyTimeout',
    'stalePreloadedIframe',
    'stalePreloadedRouter',
  ]),
  submissionSource: new Set([
    'explicit_trigger',
    'legacy_message',
    'marketo_submit',
  ]),
};
const SDK_SENTRY_SAFE_TAG_ENUM_VALUES = {
  diagnostics_version: new Set([ROUTER_DIAGNOSTICS_VERSION]),
  feature: new Set([SENTRY_FEATURE]),
  handoff_result: new Set(['ack_timeout', 'acknowledged', 'started']),
  source: new Set([SENTRY_EVENT_SOURCE]),
  submission_source: new Set([
    'explicit_trigger',
    'legacy_message',
    'marketo_submit',
  ]),
};
const SDK_SENTRY_SAFE_IDENTIFIER_PATTERN = /^[A-Za-z0-9_-]{1,160}$/;
const SDK_SENTRY_SAFE_HOST_PATTERN = /^(?=.{1,253}$)[A-Za-z0-9.-]+$/;
const SDK_SENTRY_SAFE_SECTION_PATTERN = /^[A-Za-z0-9._-]{1,160}$/;
const SDK_SENTRY_SAFE_EXCEPTION_TYPES = new Set([
  'AggregateError',
  'Error',
  'EvalError',
  'InternalError',
  'RangeError',
  'ReferenceError',
  'SyntaxError',
  'TypeError',
  'URIError',
]);
const SDK_SENTRY_ROUTER_FRAME_FILENAMES = new Set([
  'scheduler-router-integration.js',
  'scheduler-router.js',
]);
const SDK_SENTRY_MAX_ROUTER_FRAMES = 20;
const SDK_SENTRY_MAX_FRAME_POSITION = 10000000;

const getSdkExtra = (extra = {}) => ({
  pageHost: window.location.hostname,
  ...extra,
});

const getSdkTags = (section, extra = {}) => {
  const optionalTags = {
    page_host: window.location.hostname,
    router_id: extra.routerId,
    handoff_id: extra.routerMessageId,
    form_id: extra.formId,
    submission_source: extra.submissionSource,
    handoff_result: extra.handoffResult,
    diagnostics_version: extra.diagnosticsVersion,
  };

  return Object.fromEntries(
    Object.entries({
      section,
      source: SENTRY_EVENT_SOURCE,
      feature: SENTRY_FEATURE,
      ...optionalTags,
    }).filter(
      ([, value]) => value !== undefined && value !== null && value !== ''
    )
  );
};

const safelyLogSdkCaptureFailure = (level, section) => {
  const safeSection =
    typeof section === 'string' && SDK_SENTRY_SAFE_SECTION_PATTERN.test(section)
      ? section
      : 'unknown';

  try {
    console[level]?.(
      `[Avoma SDK] ${safeSection}: Sentry capture unavailable`
    );
  } catch (_error) {
    // Observability must never interrupt the customer-facing router flow.
  }
};

const captureSdkMessage = (message, section, extra = {}) => {
  try {
    const sentry = window.Sentry;
    const captureContext = {
      level: 'warning',
      tags: getSdkTags(section, extra),
      extra: getSdkExtra(extra),
    };
    if (sentry?.captureMessage) {
      sentry.captureMessage(message, captureContext);
      return;
    }
  } catch (_error) {
    // Fall through to a privacy-safe console signal.
  }

  safelyLogSdkCaptureFailure('warn', section);
};

const captureSdkException = (error, section, extra = {}) => {
  try {
    const sentry = window.Sentry;
    if (sentry?.captureException) {
      sentry.captureException(error, {
        tags: getSdkTags(section, extra),
        extra: getSdkExtra(extra),
      });
      return;
    }
  } catch (_captureError) {
    // Fall through to a privacy-safe console signal.
  }

  safelyLogSdkCaptureFailure('error', section);
};

const captureSdkDiagnostic = (message, section, handoffResult, extra = {}) => {
  try {
    const sentry = window.Sentry;
    const diagnosticExtra = {
      ...extra,
      diagnosticsVersion: ROUTER_DIAGNOSTICS_VERSION,
      handoffResult,
    };
    const captureContext = {
      level: 'info',
      tags: getSdkTags(section, diagnosticExtra),
      extra: getSdkExtra(diagnosticExtra),
    };
    if (sentry?.captureMessage) {
      sentry.captureMessage(message, captureContext);
      return;
    }
  } catch (_error) {
    // Fall through to a privacy-safe console signal.
  }

  safelyLogSdkCaptureFailure('info', section);
};

const getElement = (id) => {
  const element = document.getElementById(id);
  if (!element) {
    throw new Error(`${id} is missing`);
  }
  return element;
};

const DEFAULT_ROUTER_IFRAME_URL = 'https://book.avoma.com/router/routerid/';
const ROUTER_FRONTEND_TARGET = 'avoma-router-sdk';
const ROUTER_FRONTEND_READY_EVENT = 'routerReady';
const ROUTER_PAYLOAD_RECEIVED_EVENT = 'routerPayloadReceived';
const ROUTER_PAYLOAD_ACK_TIMEOUT_MS = 10000;
const ROUTER_IFRAME_LOAD_TIMEOUT_MS = 10000;
const ROUTER_IFRAME_READY_TIMEOUT_MS = 10000;
const ROUTER_IFRAME_MAX_RETRIES = 1;
const MARKETO_FORM_ID_PREFIX = 'mktoForm_';
const MARKETO_FORM_WARNING_TIMEOUT_MS = 10000;
const MARKETO_FORM_MAX_WAIT_MS = 30000;
const MARKETO_FORM_RETRY_INTERVAL_MS = 250;

const sanitizeUrl = (url) =>
  String(url ?? '')
    .split('?')[0]
    .split('#')[0];

const getSafeSdkHost = (value) => {
  const host = String(value ?? '');
  return SDK_SENTRY_SAFE_HOST_PATTERN.test(host) ? host : undefined;
};

const getSafeSdkUrlOrigin = (value) => {
  try {
    const url = new URL(String(value));
    if (!['http:', 'https:'].includes(url.protocol)) {
      return undefined;
    }

    const host = getSafeSdkHost(url.hostname);
    return host ? `${url.protocol}//${host}` : undefined;
  } catch (_error) {
    return undefined;
  }
};

const sanitizeSdkExtraValue = (key, value) => {
  if (SDK_SENTRY_SAFE_BOOLEAN_EXTRA_KEYS.has(key)) {
    return typeof value === 'boolean' ? value : undefined;
  }

  if (SDK_SENTRY_SAFE_NUMBER_EXTRA_KEYS.has(key)) {
    return typeof value === 'number' && Number.isFinite(value) && value >= 0
      ? value
      : undefined;
  }

  if (SDK_SENTRY_SAFE_IDENTIFIER_EXTRA_KEYS.has(key)) {
    const identifier = String(value ?? '');
    return SDK_SENTRY_SAFE_IDENTIFIER_PATTERN.test(identifier)
      ? identifier
      : undefined;
  }

  if (key === 'pageHost') {
    return getSafeSdkHost(value);
  }

  if (key === 'iframeSrc') {
    return getSafeSdkUrlOrigin(value);
  }

  const safeValues = SDK_SENTRY_SAFE_EXTRA_ENUM_VALUES[key];
  return safeValues?.has(value) ? value : undefined;
};

const sanitizeSdkTagValue = (key, value) => {
  if (['form_id', 'handoff_id', 'router_id'].includes(key)) {
    const identifier = String(value ?? '');
    return SDK_SENTRY_SAFE_IDENTIFIER_PATTERN.test(identifier)
      ? identifier
      : undefined;
  }

  if (key === 'page_host') {
    return getSafeSdkHost(value);
  }

  if (key === 'section') {
    const section = String(value ?? '');
    return SDK_SENTRY_SAFE_SECTION_PATTERN.test(section) ? section : undefined;
  }

  const safeValues = SDK_SENTRY_SAFE_TAG_ENUM_VALUES[key];
  return safeValues?.has(value) ? value : undefined;
};

const clearSdkSentryAttachments = (hint) => {
  if (!hint || typeof hint !== 'object') {
    return true;
  }

  try {
    if (hint.attachments == null) {
      return true;
    }
    if (Array.isArray(hint.attachments)) {
      hint.attachments.length = 0;
    }
    hint.attachments = [];
    return Array.isArray(hint.attachments) && hint.attachments.length === 0;
  } catch (_error) {
    // If Sentry ever provides an immutable hint, drop the event instead of
    // risking attachment data leaving the customer page.
    return false;
  }
};

const getSafeSdkFramePosition = (value, minimum) =>
  Number.isSafeInteger(value) &&
  value >= minimum &&
  value <= SDK_SENTRY_MAX_FRAME_POSITION
    ? value
    : undefined;

const getSafeSdkSchedulerRouterFilename = (frame) =>
  [frame?.filename, frame?.abs_path]
    .map((value) =>
      sanitizeUrl(value).replaceAll('\\', '/').split('/').pop()
    )
    .find((filename) => SDK_SENTRY_ROUTER_FRAME_FILENAMES.has(filename));

const sanitizeSdkExceptionFrame = (frame) => {
  const filename = getSafeSdkSchedulerRouterFilename(frame);
  if (!filename) {
    return undefined;
  }

  const sanitizedFrame = {
    filename,
    in_app: true,
  };
  const lineno = getSafeSdkFramePosition(frame.lineno, 1);
  const colno = getSafeSdkFramePosition(frame.colno, 0);
  if (lineno !== undefined) {
    sanitizedFrame.lineno = lineno;
  }
  if (colno !== undefined) {
    sanitizedFrame.colno = colno;
  }
  return sanitizedFrame;
};

const sanitizeSdkException = (exception) => {
  if (!Array.isArray(exception?.values)) {
    return undefined;
  }

  const exceptionValue = exception.values.find((value) =>
    SDK_SENTRY_SAFE_EXCEPTION_TYPES.has(value?.type)
  );
  if (!exceptionValue) {
    return undefined;
  }

  const rawFrames = exceptionValue.stacktrace?.frames;
  const frames = (Array.isArray(rawFrames) ? rawFrames : [])
    .map(sanitizeSdkExceptionFrame)
    .filter(Boolean)
    .slice(-SDK_SENTRY_MAX_ROUTER_FRAMES);
  const sanitizedValue = { type: exceptionValue.type };
  if (frames.length > 0) {
    sanitizedValue.stacktrace = { frames };
  }

  return { values: [sanitizedValue] };
};

const sanitizeSdkSentryEvent = (event, hint) => {
  try {
    if (!clearSdkSentryAttachments(hint)) {
      return null;
    }

    if (event?.tags?.source !== SENTRY_EVENT_SOURCE) {
      return null;
    }

    const extra = Object.fromEntries(
      Object.entries(event.extra || {})
        .filter(([key]) => SDK_SENTRY_SAFE_EXTRA_KEYS.has(key))
        .map(([key, value]) => [key, sanitizeSdkExtraValue(key, value)])
        .filter(([, value]) => value !== undefined)
    );
    const tags = Object.fromEntries(
      Object.entries(event.tags || {})
        .filter(([key]) => SDK_SENTRY_SAFE_TAG_KEYS.has(key))
        .map(([key, value]) => [key, sanitizeSdkTagValue(key, value)])
        .filter(([, value]) => value !== undefined)
    );
    const section = tags.section || 'unknown';
    const isException = Boolean(event.exception);
    const exception = sanitizeSdkException(event.exception);
    const sanitizedEvent = {
      extra,
      fingerprint: [SENTRY_EVENT_SOURCE, section],
      level: SDK_SENTRY_SAFE_LEVELS.has(event.level)
        ? event.level
        : isException
          ? 'error'
          : 'warning',
      message: `Avoma SDK ${isException ? 'exception' : 'event'}: ${section}`,
      platform: 'javascript',
      tags,
    };

    if (exception) {
      sanitizedEvent.exception = exception;
    }

    if (/^[a-f0-9]{32}$/i.test(event.event_id || '')) {
      sanitizedEvent.event_id = event.event_id;
    }
    if (
      typeof event.timestamp === 'number' &&
      Number.isFinite(event.timestamp)
    ) {
      sanitizedEvent.timestamp = event.timestamp;
    }

    return sanitizedEvent;
  } catch (_error) {
    // Sentry skips beforeSend for errors thrown by beforeSend itself. Always
    // drop malformed events so hostile getters/coercions cannot bypass the
    // privacy boundary through Sentry's internal-error path.
    clearSdkSentryAttachments(hint);
    return null;
  }
};

const formIdMatches = (configuredFormId, hubspotFormId) =>
  configuredFormId != null &&
  String(configuredFormId) === String(hubspotFormId);

const findUserDetailsForForm = (formId) => {
  const matchingUserDetails = Array.from(userDetailsSet)
    .reverse()
    .filter((obj) => formIdMatches(obj.formID, formId));

  return (
    matchingUserDetails.find((obj) => obj?.routerID) ??
    matchingUserDetails[0] ??
    (formIdMatches(userDetailsObj?.formID, formId) ? userDetailsObj : undefined)
  );
};

const findLatestRouterConfig = () =>
  Array.from(userDetailsSet).reverse().find((obj) => obj?.routerID);

const ensureSchedulerModalExists = () => {
  if (!document.getElementById('avoma_scheduler_modal')) {
    triggerAvomaRouter(DEFAULT_ROUTER_IFRAME_URL, true);
  }
};

const getRouterIframeAgeMs = (iframe) =>
  iframe?.__avomaCreatedAt == null
    ? undefined
    : Date.now() - iframe.__avomaCreatedAt;

const getRouterDiagnosticContexts = (iframe) => {
  if (!iframe.__avomaDiagnosticContextsByMessageId) {
    iframe.__avomaDiagnosticContextsByMessageId = new Map();
  }
  return iframe.__avomaDiagnosticContextsByMessageId;
};

const getRouterPayloadAckTimeouts = (iframe) => {
  if (!iframe.__avomaPayloadAckTimeoutsByMessageId) {
    iframe.__avomaPayloadAckTimeoutsByMessageId = new Map();
  }
  return iframe.__avomaPayloadAckTimeoutsByMessageId;
};

const getRouterHandoffState = (iframe, modal, routerMessageIdInput) => {
  const routerMessageId =
    routerMessageIdInput || iframe?.__avomaPendingMessage?.routerMessageId;
  const diagnosticContext =
    iframe?.__avomaDiagnosticContextsByMessageId?.get(routerMessageId);

  return {
    iframeSrc: sanitizeUrl(iframe?.src),
    iframeAgeMs: getRouterIframeAgeMs(iframe),
    documentVisibility: document.visibilityState,
    iframeLoaded: iframe?.dataset?.avomaLoaded,
    iframeRouterReady: iframe?.dataset?.avomaRouterReady,
    iframeVisibility: iframe?.style?.visibility,
    modalVisibility: modal?.style?.visibility,
    hasContentWindow: Boolean(iframe?.contentWindow),
    hasPendingMessage: Boolean(iframe?.__avomaPendingMessage),
    pendingMessagePosted: Boolean(iframe?.__avomaPendingMessagePosted),
    hasRouterReadyTimeout: Boolean(iframe?.__avomaRouterReadyTimeout),
    routerMessageId,
    routerId:
      diagnosticContext?.routerId || iframe?.__avomaPendingMessage?.routerId,
    formId: diagnosticContext?.formId,
    submissionSource: diagnosticContext?.submissionSource,
    diagnosticsVersion: ROUTER_DIAGNOSTICS_VERSION,
    elapsedMs:
      diagnosticContext?.startedAt == null
        ? undefined
        : Date.now() - diagnosticContext.startedAt,
    iframeRetryCount: iframe?.__avomaLoadRetryCount || 0,
    loadRetryCount: iframe?.__avomaLoadRetryCount || 0,
  };
};

const clearRouterLoadTimeout = (iframe) => {
  if (iframe?.__avomaLoadTimeout) {
    clearTimeout(iframe.__avomaLoadTimeout);
    iframe.__avomaLoadTimeout = null;
  }
};

const clearRouterPayloadAckTimeout = (iframe, routerMessageId) => {
  const ackTimeouts = iframe?.__avomaPayloadAckTimeoutsByMessageId;
  const timeout = ackTimeouts?.get(routerMessageId);
  if (!timeout) {
    return;
  }

  clearTimeout(timeout);
  ackTimeouts.delete(routerMessageId);
  if (iframe.__avomaPayloadAckTimeout === timeout) {
    iframe.__avomaPayloadAckTimeout = null;
  }
};

const clearRouterReadyTimeout = (iframe) => {
  if (iframe?.__avomaRouterReadyTimeout) {
    clearTimeout(iframe.__avomaRouterReadyTimeout);
    iframe.__avomaRouterReadyTimeout = null;
  }
};

const clearPendingRouterPayload = (iframe, routerMessageId) => {
  clearRouterReadyTimeout(iframe);
  clearRouterPayloadAckTimeout(iframe, routerMessageId);
  iframe.__avomaUnacknowledgedRouterMessageIds?.clear();
  iframe.__avomaPendingMessage = null;
  iframe.__avomaPendingMessagePosted = false;
  iframe.__avomaPayloadAckTimeout = null;
};

const getUnacknowledgedRouterMessageIds = (iframe) => {
  if (!iframe.__avomaUnacknowledgedRouterMessageIds) {
    iframe.__avomaUnacknowledgedRouterMessageIds = new Set();
  }
  return iframe.__avomaUnacknowledgedRouterMessageIds;
};

const acknowledgeRouterPayload = (iframe, routerMessageId) => {
  const unacknowledgedMessageIds = getUnacknowledgedRouterMessageIds(iframe);
  const pendingMessageId = iframe.__avomaPendingMessage?.routerMessageId;
  const acknowledgedMessageId =
    routerMessageId || unacknowledgedMessageIds.values().next().value;
  if (!acknowledgedMessageId) {
    return;
  }

  unacknowledgedMessageIds.delete(acknowledgedMessageId);
  clearRouterPayloadAckTimeout(iframe, acknowledgedMessageId);

  const diagnosticContexts = getRouterDiagnosticContexts(iframe);
  const diagnosticContext = diagnosticContexts.get(acknowledgedMessageId);
  try {
    if (diagnosticContext?.sentryDiagnostics) {
      captureSdkDiagnostic(
        'Router handoff was acknowledged by the scheduler frontend',
        'router.handoff.acknowledged',
        'acknowledged',
        getRouterHandoffState(
          iframe,
          document.getElementById('avoma_scheduler_modal'),
          acknowledgedMessageId
        )
      );
    }
  } finally {
    diagnosticContexts.delete(acknowledgedMessageId);
    if (pendingMessageId === acknowledgedMessageId) {
      clearPendingRouterPayload(iframe, acknowledgedMessageId);
    }
  }
};

var routerMessageCount = 0;
const prepareRouterMessage = (message) => ({
  ...message,
  routerMessageId:
    message?.routerMessageId ||
    `avoma-router-${Date.now()}-${++routerMessageCount}`,
});

const startRouterPayloadAckTimeout = (iframe, modal) => {
  const routerMessageId = iframe.__avomaPendingMessage?.routerMessageId;
  if (!routerMessageId) {
    return;
  }

  const ackTimeouts = getRouterPayloadAckTimeouts(iframe);
  if (ackTimeouts.has(routerMessageId)) {
    return;
  }

  const timeout = setTimeout(() => {
    if (ackTimeouts.get(routerMessageId) !== timeout) {
      return;
    }

    try {
      captureSdkException(
        new Error(
          `Scheduler iframe did not acknowledge router payload: ${sanitizeUrl(
            iframe.src
          )}`
        ),
        'showSchedulerIframe.routerPayloadAckTimeout',
        {
          ...getRouterHandoffState(iframe, modal, routerMessageId),
          handoffResult: 'ack_timeout',
        }
      );
    } finally {
      ackTimeouts.delete(routerMessageId);
      getRouterDiagnosticContexts(iframe).delete(routerMessageId);
      if (iframe.__avomaPayloadAckTimeout === timeout) {
        iframe.__avomaPayloadAckTimeout = null;
      }
    }
  }, ROUTER_PAYLOAD_ACK_TIMEOUT_MS);

  ackTimeouts.set(routerMessageId, timeout);
  iframe.__avomaPayloadAckTimeout = timeout;
};

const postPendingRouterPayload = (iframe, allowBeforeRouterReady = false) => {
  const modal = document.getElementById('avoma_scheduler_modal');
  if (
    iframe?.dataset?.avomaLoaded !== 'true' ||
    (!allowBeforeRouterReady &&
      iframe?.dataset?.avomaRouterReady !== 'true') ||
    !iframe?.contentWindow ||
    !iframe.__avomaPendingMessage ||
    iframe.__avomaPendingMessagePosted
  ) {
    return;
  }

  clearRouterReadyTimeout(iframe);
  iframe.contentWindow.postMessage(iframe.__avomaPendingMessage, '*');
  getUnacknowledgedRouterMessageIds(iframe).add(
    iframe.__avomaPendingMessage.routerMessageId
  );
  iframe.__avomaPendingMessagePosted = true;
  startRouterPayloadAckTimeout(iframe, modal);
};

const canRetryRouterIframe = (iframe) =>
  (iframe?.__avomaLoadRetryCount || 0) < ROUTER_IFRAME_MAX_RETRIES;

const getStaleRouterIframeReason = (iframe) => {
  if ((getRouterIframeAgeMs(iframe) || 0) < ROUTER_IFRAME_LOAD_TIMEOUT_MS) {
    return undefined;
  }

  if (iframe?.dataset?.avomaLoaded !== 'true') {
    return 'stalePreloadedIframe';
  }

  if (iframe?.dataset?.avomaRouterReady !== 'true') {
    return 'stalePreloadedRouter';
  }

  return undefined;
};

const replaceSchedulerIframeForRetry = (iframe, modal) => {
  const pendingMessage = iframe.__avomaPendingMessage;
  const pendingMessageId = pendingMessage?.routerMessageId;
  const diagnosticContexts = getRouterDiagnosticContexts(iframe);
  const retryCount = (iframe.__avomaLoadRetryCount || 0) + 1;
  const iframeSrc = iframe.src || DEFAULT_ROUTER_IFRAME_URL;

  clearRouterLoadTimeout(iframe);
  clearRouterReadyTimeout(iframe);
  clearRouterPayloadAckTimeout(iframe, pendingMessageId);
  iframe.__avomaPendingMessage = null;
  iframe.__avomaPendingMessagePosted = false;

  const retryIframe = createIframe(iframeSrc, false);
  retryIframe.__avomaLoadRetryCount = retryCount;
  retryIframe.__avomaPendingMessage = pendingMessage;
  retryIframe.__avomaPendingMessagePosted = false;
  retryIframe.__avomaDiagnosticContextsByMessageId = diagnosticContexts;

  iframe.remove();
  modal.appendChild(retryIframe);
  return retryIframe;
};

const retrySchedulerIframe = (iframe, modal, retryReason) => {
  const isRouterReadyRetry =
    retryReason === 'routerReadyTimeout' ||
    retryReason === 'stalePreloadedRouter';

  captureSdkMessage(
    isRouterReadyRetry
      ? 'Scheduler iframe loaded but router was not ready; retrying iframe'
      : 'Scheduler iframe did not load; retrying iframe load',
    isRouterReadyRetry
      ? 'showSchedulerIframe.routerReadyRetry'
      : 'showSchedulerIframe.iframeLoadRetry',
    {
      ...getRouterHandoffState(iframe, modal),
      retryReason,
    }
  );

  return replaceSchedulerIframeForRetry(iframe, modal);
};

const scheduleRouterIframeLoadTimeout = (iframe, modal) => {
  clearRouterLoadTimeout(iframe);
  iframe.__avomaLoadTimeout = setTimeout(() => {
    if (
      iframe.dataset.avomaLoaded === 'true' ||
      !iframe.__avomaPendingMessage
    ) {
      iframe.__avomaLoadTimeout = null;
      return;
    }

    if (canRetryRouterIframe(iframe)) {
      const retryIframe = retrySchedulerIframe(iframe, modal, 'loadTimeout');
      scheduleRouterIframeLoadTimeout(retryIframe, modal);
      return;
    }

    captureSdkException(
      new Error(
        `Scheduler iframe did not load after popup open: ${sanitizeUrl(
          iframe.src
        )}`
      ),
      'showSchedulerIframe.iframeLoadTimeout',
      getRouterHandoffState(iframe, modal)
    );
    iframe.__avomaLoadTimeout = null;
  }, ROUTER_IFRAME_LOAD_TIMEOUT_MS);
};

const startRouterReadyTimeout = (iframe, modal) => {
  if (
    !iframe?.__avomaPendingMessage ||
    iframe.__avomaPendingMessagePosted ||
    iframe.dataset.avomaLoaded !== 'true' ||
    iframe.dataset.avomaRouterReady === 'true' ||
    iframe.__avomaRouterReadyTimeout
  ) {
    return;
  }

  iframe.__avomaRouterReadyTimeout = setTimeout(() => {
    iframe.__avomaRouterReadyTimeout = null;

    if (!iframe.__avomaPendingMessage || iframe.__avomaPendingMessagePosted) {
      return;
    }

    if (iframe.dataset.avomaRouterReady === 'true') {
      postPendingRouterPayload(iframe);
      return;
    }

    if (canRetryRouterIframe(iframe)) {
      const retryIframe = retrySchedulerIframe(
        iframe,
        modal,
        'routerReadyTimeout'
      );
      scheduleRouterPayloadDelivery(retryIframe, modal);
      return;
    }

    captureSdkMessage(
      'Scheduler iframe did not announce router readiness; using compatibility handoff',
      'showSchedulerIframe.routerReadyFallback',
      getRouterHandoffState(iframe, modal)
    );
    postPendingRouterPayload(iframe, true);
  }, ROUTER_IFRAME_READY_TIMEOUT_MS);
};

const scheduleRouterPayloadDelivery = (iframe, modal) => {
  if (!iframe?.__avomaPendingMessage || iframe.__avomaPendingMessagePosted) {
    return;
  }

  if (iframe.dataset.avomaLoaded !== 'true' || !iframe.contentWindow) {
    scheduleRouterIframeLoadTimeout(iframe, modal);
    return;
  }

  if (iframe.dataset.avomaRouterReady === 'true') {
    postPendingRouterPayload(iframe);
    return;
  }

  startRouterReadyTimeout(iframe, modal);
};

const showSchedulerIframe = (message, diagnosticContext = {}) => {
  ensureSchedulerModalExists();
  let iframe = getElement('avoma_scheduler_iframe');
  const modal = getElement('avoma_scheduler_modal');

  iframe.style.visibility = 'visible';
  modal.style.visibility = 'visible';

  // The router iframe can still be booting when HubSpot fires the submit
  // callback, so queue the payload until the iframe is loaded and ready.
  const diagnosticContexts = getRouterDiagnosticContexts(iframe);
  const previousPendingMessageId =
    iframe.__avomaPendingMessage?.routerMessageId;
  if (previousPendingMessageId && !iframe.__avomaPendingMessagePosted) {
    clearRouterPayloadAckTimeout(iframe, previousPendingMessageId);
    diagnosticContexts.delete(previousPendingMessageId);
  }

  clearRouterReadyTimeout(iframe);
  iframe.__avomaPendingMessage = prepareRouterMessage({
    ...message,
    ...(diagnosticContext.sentryDiagnostics
      ? { sentryDiagnostics: true }
      : {}),
  });
  iframe.__avomaPendingMessagePosted = false;
  iframe.__avomaPayloadAckTimeout = null;

  const routerMessageId = iframe.__avomaPendingMessage.routerMessageId;
  const pendingDiagnosticContext = {
    formId: diagnosticContext.formId,
    routerId: message.routerId,
    sentryDiagnostics: Boolean(diagnosticContext.sentryDiagnostics),
    startedAt: Date.now(),
    submissionSource: diagnosticContext.submissionSource,
  };
  diagnosticContexts.set(routerMessageId, pendingDiagnosticContext);

  if (pendingDiagnosticContext.sentryDiagnostics) {
    captureSdkDiagnostic(
      'Router handoff started after a matching form submission',
      'router.handoff.started',
      'started',
      getRouterHandoffState(iframe, modal)
    );
  }

  const staleIframeReason = getStaleRouterIframeReason(iframe);
  if (canRetryRouterIframe(iframe) && staleIframeReason) {
    iframe = retrySchedulerIframe(iframe, modal, staleIframeReason);
  }

  scheduleRouterPayloadDelivery(iframe, modal);

  if (
    modal.style.visibility !== 'visible' ||
    iframe.style.visibility !== 'visible'
  ) {
    captureSdkException(
      new Error('Scheduler modal was not opened'),
      'showSchedulerIframe.modalVisibility',
      {
        iframeVisibility: iframe.style.visibility,
        modalVisibility: modal.style.visibility,
      }
    );
  }
};

const initializeSentry = () => {
  window.sentryOnLoad = () => {
    window.Sentry.init({
      beforeSend: sanitizeSdkSentryEvent,
    });
  };

  const script = document.createElement('script');
  script.src =
    'https://js.sentry-cdn.com/589b562413054dd0801bb0f23b9ac964.min.js';
  script.crossOrigin = 'anonymous';
  document.head.appendChild(script);
};

const getUTMParams = () => {
  const currentUrl = new URL(window.location.href);
  const utmParams = {};
  UTMParams.forEach((param) => {
    const paramLower = param.toLowerCase();

    const value = Array.from(currentUrl.searchParams.entries()).find(
      ([key]) => key.toLowerCase() === paramLower
    )?.[1];
    if (value) {
      utmParams[param] = value;
    }
  });
  return utmParams;
};

initializeSentry();
var userDetailsSet = new Set();
var userDetailsObj;
var utmParams = {};
var unmatchedHubspotSubmissionFormIds = new Set();
var marketoFormListenerStateById = new Map();

const hasRegisteredFormRouterConfig = () =>
  Array.from(userDetailsSet).some((obj) => obj?.routerID && obj?.formID);

const captureUnmatchedHubspotSubmission = (formId) => {
  if (!hasRegisteredFormRouterConfig()) {
    return;
  }

  const dedupeKey = String(formId ?? 'unknown-form-id');
  if (unmatchedHubspotSubmissionFormIds.has(dedupeKey)) {
    return;
  }
  unmatchedHubspotSubmissionFormIds.add(dedupeKey);

  captureSdkMessage(
    'HubSpot submitted callback did not match any Avoma router configuration',
    'window.message.hubspotFormNotMatched',
    {
      formId,
      registeredRouterCount: userDetailsSet.size,
    }
  );
};

const isMarketoFormId = (formId) =>
  typeof formId === 'string' && formId.startsWith(MARKETO_FORM_ID_PREFIX);

const getMarketoFormListenerState = (formId) => {
  const existingState = marketoFormListenerStateById.get(formId);
  if (existingState) {
    return existingState;
  }

  const state = {
    didCaptureMissingForm: false,
    isListening: false,
    registrationSource: undefined,
    retryTimeoutId: null,
    startedAt: Date.now(),
    userDetailsObj: undefined,
  };
  marketoFormListenerStateById.set(formId, state);
  return state;
};

const getMarketoFormExtra = (formId, state, extra = {}) => ({
  formId,
  routerId: state?.userDetailsObj?.routerID,
  registrationSource: state?.registrationSource,
  registeredRouterCount: userDetailsSet.size,
  hasMktoForms2: Boolean(window.MktoForms2),
  ...extra,
});

const captureMissingMarketoForm = (formId, state, waitMs) => {
  if (state.didCaptureMissingForm) {
    return;
  }

  state.didCaptureMissingForm = true;
  captureSdkMessage(
    'Marketo form element was not found after router registration',
    'Avoma.marketoIntegration.formElementMissing',
    getMarketoFormExtra(formId, state, { waitMs })
  );
};

const getMarketoFormPayload = (formElement) => {
  const params = new URLSearchParams();
  Array.from(new FormData(formElement).entries()).forEach(([key, value]) => {
    params.append(key, value);
  });
  return params.toString();
};

const attachMarketoSubmitListener = (formElement, formId, state) => {
  if (state.isListening) {
    return;
  }

  formElement.addEventListener('submit', (event) => {
    try {
      const routerId = state.userDetailsObj?.routerID;
      if (!routerId) {
        captureSdkMessage(
          'Marketo form submitted without registered router configuration',
          'Avoma.marketoIntegration.missingRouterConfig',
          getMarketoFormExtra(formId, state)
        );
        return;
      }

      showSchedulerIframe(
        {
          type: 1,
          payload: getMarketoFormPayload(event.target),
          routerId,
          directTo: 'avoma',
        },
        {
          formId,
          sentryDiagnostics: Boolean(state.userDetailsObj?.sentryDiagnostics),
          submissionSource: 'marketo_submit',
        }
      );
    } catch (error) {
      captureSdkException(
        error,
        'Avoma.marketoIntegration.submit',
        getMarketoFormExtra(formId, state)
      );
    }
  });

  state.isListening = true;
  if (state.retryTimeoutId) {
    clearTimeout(state.retryTimeoutId);
    state.retryTimeoutId = null;
  }
};

const waitForMarketoFormElement = (formId, state) => {
  if (state.isListening) {
    return;
  }

  const marketoFormElement = document.getElementById(formId);
  if (marketoFormElement) {
    attachMarketoSubmitListener(marketoFormElement, formId, state);
    return;
  }

  const waitMs = Date.now() - state.startedAt;
  if (waitMs >= MARKETO_FORM_WARNING_TIMEOUT_MS) {
    captureMissingMarketoForm(formId, state, waitMs);
  }

  if (waitMs >= MARKETO_FORM_MAX_WAIT_MS) {
    return;
  }

  if (state.retryTimeoutId) {
    clearTimeout(state.retryTimeoutId);
  }
  state.retryTimeoutId = setTimeout(() => {
    state.retryTimeoutId = null;
    waitForMarketoFormElement(formId, state);
  }, MARKETO_FORM_RETRY_INTERVAL_MS);
};

const registerMarketoFormListener = (userDetailsObjInput, registrationSource) => {
  const formId = String(userDetailsObjInput?.formID ?? '');
  if (!userDetailsObjInput?.routerID || !isMarketoFormId(formId)) {
    return;
  }

  const state = getMarketoFormListenerState(formId);
  state.userDetailsObj = userDetailsObjInput;
  state.registrationSource = registrationSource;
  if (!state.isListening) {
    state.startedAt = Date.now();
    state.didCaptureMissingForm = false;
    waitForMarketoFormElement(formId, state);
  }
};

const registerRouterConfig = (userDetailsObjInput, registrationSource) => {
  // setUserDetails existed before router-only embeds and can be used by
  // legacy pages to provide UTM/metadata without a router configuration.
  // Keep the missing-router warning scoped to the newer explicit router API.
  if (!userDetailsObjInput?.routerID && registrationSource !== 'setUserDetails') {
    captureSdkMessage(
      'Router configuration is missing routerID',
      `Avoma.${registrationSource}.missingRouterId`,
      {
        formId: userDetailsObjInput?.formID,
        registrationSource,
      }
    );
  }

  userDetailsSet.add(userDetailsObjInput);
  userDetailsObj = userDetailsObjInput;
  utmParams = userDetailsObjInput?.utm ?? getUTMParams();
  registerMarketoFormListener(userDetailsObjInput, registrationSource);
};
Avoma.setUserDetails = (userDetailsObj1) =>
  registerRouterConfig(userDetailsObj1, 'setUserDetails');
var lead = {};
var count = 0;
window.addEventListener('message', function (event) {
  try {
    if (event.data?.directTo === ROUTER_FRONTEND_TARGET) {
      const iframe = document.getElementById('avoma_scheduler_iframe');
      if (!iframe) {
        return;
      }

      if (event.source && event.source !== iframe.contentWindow) {
        return;
      }

      if (event.data.eventName === ROUTER_FRONTEND_READY_EVENT) {
        iframe.dataset.avomaRouterReady = 'true';
        clearRouterReadyTimeout(iframe);
        postPendingRouterPayload(iframe);
        return;
      }

      if (event.data.eventName === ROUTER_PAYLOAD_RECEIVED_EVENT) {
        acknowledgeRouterPayload(iframe, event.data.routerMessageId);
        return;
      }
    }

    if (event.data.type === 'hsFormCallback') {
      const matchedUserDetails = findUserDetailsForForm(event.data.id);
      if (matchedUserDetails?.routerID) {
        if (event.data.eventName === 'onFormSubmit') {
          lead = handleFormData(event);
        } else if (event.data.eventName === 'onFormSubmitted') {
          const urlparams = new URLSearchParams({
            ...lead,
            ...utmParams,
          }).toString();

          const { routerID: routerId } = matchedUserDetails;
          showSchedulerIframe(
            {
              type: 1,
              payload: urlparams,
              routerId,
              directTo: 'avoma',
            },
            {
              formId: event.data.id,
              sentryDiagnostics: Boolean(
                matchedUserDetails.sentryDiagnostics
              ),
              submissionSource: 'legacy_message',
            }
          );
        }
      } else if (event.data.eventName === 'onFormSubmitted') {
        captureUnmatchedHubspotSubmission(event.data.id);
      }
    } else if (event.data.type === 'avBookingCallback') {
      const meetingDetails = event.data.meetingDetails;
      if (typeof onBookingConfirmation === 'function') {
        try {
          onBookingConfirmation(meetingDetails);
        } catch (error) {
          console.error('[Avoma SDK] onBookingConfirmation failed', error);
        }
      }
    }
  } catch (error) {
    captureSdkException(error, 'window.message');
  }
});
Avoma.triggerRouter = (data) => {
  try {
    const params = new URLSearchParams(data).toString();
    const triggeredUserDetailsObj = findLatestRouterConfig();
    const routerId = triggeredUserDetailsObj?.routerID;

    if (!routerId) {
      captureSdkMessage(
        'Router handoff attempted without registered router configuration',
        'Avoma.triggerRouter.missingRouterConfig',
        {
          hasSubmissionValues: Boolean(data && Object.keys(data).length > 0),
          registeredRouterCount: userDetailsSet.size,
        }
      );
      return;
    }

    const message = {
      type: 1,
      payload: params,
      routerId: routerId,
      directTo: 'avoma',
    };
    showSchedulerIframe(message, {
      formId: triggeredUserDetailsObj?.formID,
      sentryDiagnostics: Boolean(
        triggeredUserDetailsObj?.sentryDiagnostics
      ),
      submissionSource: 'explicit_trigger',
    });
  } catch (error) {
    captureSdkException(error, 'Avoma.triggerRouter');
  }
};
Avoma.onFormSubmitted = function ($form, data) {
  Avoma.triggerRouter(data?.submissionValues || {});
};
const triggerAvomaRouter = (url, isHidden = false) => {
  try {
    const modal = createModal(isHidden);
    const frame = createIframe(url, isHidden);
    modal.appendChild(frame);
    window.addEventListener('message', (event) => {
      if (event.data === 'Please close react app, thank you !') {
        const iframe = getElement('avoma_scheduler_iframe');
        iframe.style.visibility = 'hidden';
        const modal = getElement('avoma_scheduler_modal');
        modal.style.visibility = 'hidden';
      }
    });
    document.body.appendChild(modal);
  } catch (error) {
    captureSdkException(error, 'triggerAvomaRouter');
  }
};

const unMountAvomaRouter = () => {
  const iframe = document.getElementById('avoma_scheduler_iframe');
  if (!iframe) {
    return;
  }
  const defaultRouterUrls = [
    DEFAULT_ROUTER_IFRAME_URL,
    'https://int-8967-book.avoma.com/router/routerid/',
  ];
  if (defaultRouterUrls.includes(iframe.src)) {
    const modal = iframe.parentElement;
    iframe.remove();
    modal?.remove();
  }
};

const openModal = (modal) => {
  modal.style.display = modal.style.display === !'none' ? 'block' : 'none';
};
const generateCloseButton = (openModal, modal) => {
  var closeButton = document.createElement('button');
  closeButton.style.width = '3rem';
  closeButton.textContent = 'X';
  closeButton.style.borderRadius = '3rem';
  closeButton.style.border = 'none';
  closeButton.style.fontSize = '2rem';
  closeButton.style.margin = '1rem';
  closeButton.style.position = 'absolute';
  closeButton.style.right = '0';

  closeButton.addEventListener('click', () => openModal(modal));
  return closeButton;
};
const createModal = (isHidden = false) => {
  const modal = document.createElement('div');
  modal.id = 'avoma_scheduler_modal';
  modal.classList.add('avoma-modal');
  modal.style.display = 'block';
  modal.style.position = 'fixed';
  modal.style.top = 0;
  // modal.style.left = 0;
  modal.style.overflow = 'auto';
  modal.style.zIndex = 9999999;
  modal.style.width = '100%';
  modal.style.height = '100%';
  modal.style.overflow = 'hidden';
  modal.style.background = 'rgba(0, 0, 0, 0.5)';
  modal.style.visibility = isHidden ? 'hidden' : 'visible';
  return modal;
};
const createIframe = (url, isHidden = false) => {
  var iframe = document.createElement('iframe');
  iframe.style.width = '100%';
  iframe.style.height = '100%';
  iframe.style.border = 'none';
  iframe.dataset.avomaLoaded = 'false';
  iframe.dataset.avomaRouterReady = 'false';
  iframe.__avomaCreatedAt = Date.now();
  iframe.__avomaLoadRetryCount = 0;

  iframe.addEventListener('load', () => {
    clearRouterLoadTimeout(iframe);

    iframe.dataset.avomaLoaded = 'true';
    const modal = document.getElementById('avoma_scheduler_modal');
    scheduleRouterPayloadDelivery(iframe, modal);
  });
  iframe.addEventListener('error', () => {
    if (iframe.__avomaPendingMessage || iframe.style.visibility === 'visible') {
      captureSdkException(
        new Error(`Scheduler iframe failed to load: ${sanitizeUrl(url)}`),
        'createIframe.error',
        {
          iframeLoaded: iframe.dataset.avomaLoaded,
          iframeVisibility: iframe.style.visibility,
        }
      );
    }
  });

  iframe.src = url;
  iframe.id = 'avoma_scheduler_iframe';
  iframe.sandbox =
    'allow-popups allow-scripts allow-same-origin allow-top-navigation';
  iframe.style.visibility = isHidden ? 'hidden' : 'visible';
  return iframe;
};

const handleFormData = (event) => {
  for (var key in event.data.data) {
    if (Array.isArray(event.data.data[key].value)) {
      event.data.data[key].value = event.data.data[key].value
        .toString()
        .replaceAll(',', ';');
    }
    lead[event.data.data[key].name] = event.data.data[key].value;
  }
  if (Object.keys(lead).length <= 1) {
    lead = event.data.data;
  }
  delete lead.hs_context;

  return lead;
};
triggerAvomaRouter(DEFAULT_ROUTER_IFRAME_URL, true);

// INLINE SCRIPT
// user should be able to put a div with class avoma-scheduler
// and the script should render the iframe inside that div

// find div with class avoma-scheduler

const avomaSchedulerDiv = document.getElementsByClassName('avoma-scheduler');

const renderSchedulingPage = (url, div) => {
  const frame = createIframe(url);
  if (!div) {
    console.error('div for rendering scheduling page is missing');
  } else {
    div.style.width = '860px';
    div.style.height = '600px';
    div.appendChild(frame);
  }
};

const addUTMValues = (url) => {
  const utmParams = getUTMParams();
  const newUrl = new URL(url);

  Object.entries(utmParams).forEach(([key, value]) => {
    newUrl.searchParams.set(key, value);
  });

  return newUrl.toString();
};

Array.from(avomaSchedulerDiv).forEach((div) => {
  const url = div.getAttribute('avoma-scheduler-url');

  const urlWithUTM = addUTMValues(url);

  if (!url) {
    console.error('avoma-scheduler-url attribute is missing');
    return;
  }
  if (url) {
    renderSchedulingPage(urlWithUTM, div);
  }
  // triggerAvomaRouter(url, isHidden);
});

// Popup script
// user should get a button to trigger scheduler page
// modal , iframe should be created on click of that button

// find div with class avoma-scheduler-button
// add clickhandler to it
// hit trigger router call on the attributes of that div

const avomaSchedulerButton = document.getElementsByClassName(
  'avoma-scheduler-button'
);

Array.from(avomaSchedulerButton).forEach((button) => {
  button.addEventListener('click', () => {
    // two avoma instances were getting rendered due to script preloading router/routerid one as well.
    // so if popup is triggerd simply remove the router/routerid instance

    try {
      unMountAvomaRouter();
    } catch (error) {
      console.log(error);
    }

    let sch_url = button.getAttribute('avoma-scheduler-url');
    triggerAvomaRouter(sch_url);
  });
});

try {
  Avoma.initRouter = (userDetailsObjInput) => {
    registerRouterConfig(userDetailsObjInput, 'initRouter');
  };
} catch (error) {
  captureSdkException(error, 'Avoma.initRouter');
}
