/*
 * Copyright 2024 Adobe. All rights reserved.
 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. You may obtain a copy
 * of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under
 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
 * OF ANY KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
(function () {
  'use strict';

  const h = (s, a) => [...s].reduce((p, c) => p + c.charCodeAt(0), a) % 1371;
  const fflags = {
    has: (f) => fflags[f].includes(h(window.origin, 1)) || /localhost/.test(window.origin),
    enabled: (f, c) => fflags.has(f) && c(),
    disabled: (f, c) => !fflags.has(f) && c(),
    eagercwv: [683],
    redirect: [620, 1139],
    example: [543, 770, 1136],
    language: [543, 959, 1139, 620],
    allresources: [1139],
  };

  const KNOWN_PROPERTIES = ['weight', 'id', 'referer', 'checkpoint', 't', 'source', 'target', 'cwv', 'CLS', 'FID', 'LCP', 'INP', 'TTFB'];
  const DEFAULT_TRACKING_EVENTS = ['click', 'cwv', 'form', 'viewblock', 'viewmedia', 'loadresource', 'utm', 'paid', 'email', 'consent'];
  fflags.enabled('example', () => DEFAULT_TRACKING_EVENTS.push('example'));

  const { href } = window.location;
  const urlSanitizers = {
    full: (url = href) => new URL(url).toString(),
    origin: (url = href) => new URL(url).origin,
    path: (url = href) => {
      const u = new URL(url);
      return `${u.origin}${u.pathname}`;
    },
  };

  const getTargetValue = (el) => el.getAttribute('data-rum-target') || el.getAttribute('href')
      || el.currentSrc || el.getAttribute('src') || el.dataset.action || el.action;
  const targetSelector = (el) => {
    try {
      if (!el) return undefined;
      let v = getTargetValue(el);
      if (!v && el.tagName !== 'A' && el.closest('a')) {
        v = getTargetValue(el.closest('a'));
      }
      if (v && !v.startsWith('https://')) {
        v = new URL(v, window.location).href;
      }
      return v;
    } catch (error) {
      return null;
    }
  };
  function walk(el, checkFn) {
    if (!el || el === document.body || el === document.documentElement) {
      return undefined;
    }
    return checkFn(el) || walk(el.parentElement, checkFn);
  }
  function isDialog(el) {
    if (el.tagName === 'DIALOG') return true;
    const cs = window.getComputedStyle(el);
    return ['dialog', 'alertdialog'].find((r) => el.getAttribute('role') === r)
      || el.getAttribute('aria-modal') === 'true'
      || (cs && cs.position === 'fixed' && cs.zIndex > 100);
  }
  function isButton(el) {
    if (el.tagName === 'BUTTON') return true;
    if (el.tagName === 'INPUT' && el.getAttribute('type') === 'button') return true;
    if (el.tagName === 'A') {
      const classes = Array.from(el.classList);
      return classes.some((className) => className.match(/button|cta/));
    }
    return el.getAttribute('role') === 'button';
  }
  function getSourceContext(el) {
    const formEl = el.closest('form');
    if (formEl) {
      const id = formEl.getAttribute('id');
      return `form${id ? `#${id}` : ''}`;
    }
    const block = el.closest('.block[data-block-name]');
    return ((block && `.${block.getAttribute('data-block-name')}`)
      || (walk(el, isDialog) && 'dialog')
      || ['nav', 'header', 'footer', 'aside'].find((t) => el.closest(t))
      || walk(el, (e) => e.id && `#${e.id}`));
  }
  function getSourceElement(el) {
    const f = el.closest('form');
    if (f && Array.from(f.elements).includes(el)) {
      return (el.tagName.toLowerCase()
          + (['INPUT', 'BUTTON'].includes(el.tagName)
            ? `[type='${el.getAttribute('type') || ''}']`
            : ''));
    }
    if (walk(el, isButton)) return 'button';
    return el.tagName.toLowerCase().match(/^(a|img|video)$/) && el.tagName.toLowerCase();
  }
  function getSourceIdentifier(el) {
    if (el.id) return `#${el.id}`;
    if (el.getAttribute('data-block-name')) return `.${el.getAttribute('data-block-name')}`;
    return (el.classList.length > 0 && `.${el.classList[0]}`);
  }
  const sourceSelector = (el) => {
    try {
      if (!el || el === document.body || el === document.documentElement) {
        return undefined;
      }
      if (el.getAttribute('data-rum-source')) {
        return el.getAttribute('data-rum-source');
      }
      const ctx = getSourceContext(el.parentElement) || '';
      const name = getSourceElement(el) || '';
      const id = getSourceIdentifier(el) || '';
      return `${ctx} ${name}${id}`.trim() || `"${el.textContent.substring(0, 10)}"`;
    } catch (error) {
      return null;
    }
  };

  function addCookieConsentTracking(sampleRUM) {
    const cmpCookie = document.cookie.split(';')
      .map((c) => c.trim())
      .find((cookie) => cookie.startsWith('OptanonAlertBoxClosed='));
    if (cmpCookie) {
      sampleRUM('consent', { source: 'onetrust', target: 'hidden' });
      return;
    }
    let consentMO;
    const trackShowConsent = () => {
      const otsdk = document.querySelector('body > div#onetrust-consent-sdk');
      if (otsdk) {
        if (otsdk.checkVisibility && !otsdk.checkVisibility()) {
          sampleRUM('consent', { source: 'onetrust', target: 'suppressed' });
        } else {
          sampleRUM('consent', { source: 'onetrust', target: 'show' });
        }
        if (consentMO) {
          consentMO.disconnect();
        }
        return true;
      }
      return false;
    };
    if (!trackShowConsent()) {
      consentMO = window.MutationObserver
        ? new MutationObserver(trackShowConsent)
        :  null;
      if (consentMO) {
        consentMO.observe(
          document.body,
          { attributes: false, childList: true, subtree: false },
        );
      }
    }
  }
  function addUTMParametersTracking(sampleRUM) {
    const usp = new URLSearchParams(window.location.search);
    [...usp.entries()]
      .filter(([key]) => key.startsWith('utm_'))
      .filter(([key]) => key !== 'utm_id')
      .filter(([key]) => key !== 'utm_term')
      .forEach(([source, target]) => sampleRUM('utm', { source, target }));
  }
  function addAdsParametersTracking(sampleRUM) {
    const networks = {
      google: /gclid|gclsrc|wbraid|gbraid/,
      doubleclick: /dclid/,
      microsoft: /msclkid/,
      facebook: /fb(cl|ad_|pxl_)id/,
      twitter: /tw(clid|src|term)/,
      linkedin: /li_fat_id/,
      pinterest: /epik/,
      tiktok: /ttclid/,
    };
    const params = Array.from(new URLSearchParams(window.location.search).keys());
    Object.entries(networks).forEach(([network, regex]) => {
      params.filter((param) => regex.test(param)).forEach((param) => sampleRUM('paid', { source: network, target: param }));
    });
  }
  function addEmailParameterTracking(sampleRUM) {
    const networks = {
      mailchimp: /mc_(c|e)id/,
      marketo: /mkt_tok/,
    };
    const params = Array.from(new URLSearchParams(window.location.search).keys());
    Object.entries(networks).forEach(([network, regex]) => {
      params.filter((param) => regex.test(param)).forEach((param) => sampleRUM('email', { source: network, target: param }));
    });
  }

  const { sampleRUM, queue, isSelected } = (window.hlx && window.hlx.rum) ? window.hlx.rum
     : {};
  const blocksMO = window.MutationObserver ? new MutationObserver(blocksMCB)
     : {};
  const mediaMO = window.MutationObserver ? new MutationObserver(mediaMCB)
     : {};
  let maxEvents = 1023;
  function trackCheckpoint(checkpoint, data, t) {
    const { weight, id } = window.hlx.rum;
    if (isSelected && maxEvents) {
      maxEvents -= 1;
      const sendPing = (pdata = data) => {
        const body = JSON.stringify({ weight, id, referer: urlSanitizers[window.hlx.RUM_MASK_URL || 'path'](), checkpoint, t, ...data }, KNOWN_PROPERTIES);
        const urlParams = window.RUM_PARAMS ? `?${new URLSearchParams(window.RUM_PARAMS).toString()}` : '';
        const { href: url, origin } = new URL(`.rum/${weight}${urlParams}`, sampleRUM.collectBaseURL);
        if (window.location.origin === origin) {
          const headers = { type: 'application/json' };
          navigator.sendBeacon(url, new Blob([body], headers));
        } else {
          navigator.sendBeacon(url, body);
        }
        console.debug(`ping:${checkpoint}`, pdata);
      };
      sendPing(data);
    }
  }
  function processQueue() {
    while (queue && queue.length) {
      const ck = queue.shift();
      trackCheckpoint(...ck);
    }
  }
  function addCWVTracking() {
    setTimeout(() => {
      try {
        const cwvScript = new URL('.rum/web-vitals/dist/web-vitals.iife.js', sampleRUM.baseURL).href;
        if (document.querySelector(`script[src="${cwvScript}"]`)) {
          return;
        }
        const script = document.createElement('script');
        script.src = cwvScript;
        script.onload = () => {
          const storeCWV = (measurement) => {
            const data = { cwv: {} };
            data.cwv[measurement.name] = measurement.value;
            if (measurement.name === 'LCP' && measurement.entries.length > 0) {
              const { element } = measurement.entries.pop();
              data.target = targetSelector(element);
              data.source = sourceSelector(element) || (element && element.outerHTML.slice(0, 30));
            }
            sampleRUM('cwv', data);
          };
          const isEager = (metric) => ['CLS', 'LCP'].includes(metric);
          ['INP', 'TTFB', 'CLS', 'LCP'].forEach((metric) => {
            const metricFn = window.webVitals[`on${metric}`];
            if (typeof metricFn === 'function') {
              let opts = {};
              fflags.enabled('eagercwv', () => {
                opts = { reportAllChanges: isEager(metric) };
              });
              metricFn(storeCWV, opts);
            }
          });
        };
        document.head.appendChild(script);
      } catch (error) {
      }
    }, 2000);
  }
  function addNavigationTracking() {
    const navigate = (source, type, redirectCount) => {
      const payload = { source, target: document.visibilityState };
      if (document.prerendering) {
        document.addEventListener('prerenderingchange', () => {
          payload.target = 'prerendered';
          sampleRUM('navigate', payload);
        }, {
          once: true,
        });
        if (type === 'navigate') {
          sampleRUM('prerender', payload);
        }
      } else if (type === 'reload' || source === window.location.href) {
        sampleRUM('reload', payload);
      } else if (type && type !== 'navigate') {
        sampleRUM(type, payload);
      } else if (source && window.location.origin === new URL(source).origin) {
        sampleRUM('navigate', payload);
      } else {
        sampleRUM('enter', payload);
      }
      fflags.enabled('redirect', () => {
        const from = new URLSearchParams(window.location.search).get('redirect_from');
        if (redirectCount || from) {
          sampleRUM('redirect', { source: from, target: redirectCount || 1 });
        }
      });
    };
    const processed = new Set();
    new PerformanceObserver((list) => list
      .getEntries()
      .filter(({ type }) => !processed.has(type))
      .map((e) => [e, processed.add(e.type)])
      .map(([e]) => navigate(
        window.hlx.referrer || document.referrer,
        e.type,
        e.redirectCount,
      ))).observe({ type: 'navigation', buffered: true });
  }
  function addLoadResourceTracking() {
    const observer = new PerformanceObserver((list) => {
      try {
        list.getEntries()
          .filter((e) => !e.responseStatus || e.responseStatus < 400)
          .filter((e) => window.location.hostname === new URL(e.name).hostname || fflags.has('allresources'))
          .filter((e) => new URL(e.name).pathname.match('.*(\\.plain\\.html$|\\.json|graphql|api)'))
          .forEach((e) => {
            sampleRUM('loadresource', { source: e.name, target: Math.round(e.duration) });
          });
        list.getEntries()
          .filter((e) => e.responseStatus >= 400)
          .forEach((e) => {
            sampleRUM('missingresource', { source: e.name, target: e.responseStatus });
          });
      } catch (error) {
      }
    });
    observer.observe({ type: 'resource', buffered: true });
  }
  function activateBlocksMO() {
    if (!blocksMO || blocksMO.active) {
      return;
    }
    blocksMO.active = true;
    blocksMO.observe(
      document.body,
      { subtree: true, attributes: true, attributeFilter: ['data-block-status'] },
    );
  }
  function activateMediaMO() {
    if (!mediaMO || mediaMO.active) {
      return;
    }
    mediaMO.active = true;
    mediaMO.observe(
      document.body,
      { subtree: true, attributes: false, childList: true },
    );
  }
  function getIntersectionObsever(checkpoint) {
    if (!window.IntersectionObserver) {
      return null;
    }
    activateBlocksMO();
    activateMediaMO();
    const observer = new IntersectionObserver((entries) => {
      try {
        entries
          .filter((e) => e.isIntersecting)
          .forEach((e) => {
            observer.unobserve(e.target);
            const target = targetSelector(e.target);
            const source = sourceSelector(e.target);
            sampleRUM(checkpoint, { target, source });
          });
      } catch (error) {
      }
    });
    return observer;
  }
  function addViewBlockTracking(element) {
    const blockobserver = getIntersectionObsever('viewblock');
    if (blockobserver) {
      const blocks = element.getAttribute('data-block-status') ? [element] : element.querySelectorAll('div[data-block-status="loaded"]');
      blocks.forEach((b) => blockobserver.observe(b));
    }
  }
  const observedMedia = new Set();
  function addViewMediaTracking(parent) {
    const mediaobserver = getIntersectionObsever('viewmedia');
    if (mediaobserver) {
      parent.querySelectorAll('img, video, audio, iframe').forEach((m) => {
        if (!observedMedia.has(m)) {
          observedMedia.add(m);
          mediaobserver.observe(m);
        }
      });
    }
  }
  function addFormTracking(parent) {
    activateBlocksMO();
    activateMediaMO();
    parent.querySelectorAll('form').forEach((form) => {
      form.addEventListener('submit', (e) => sampleRUM('formsubmit', { target: targetSelector(e.target), source: sourceSelector(e.target) }), { once: true });
      let lastSource;
      form.addEventListener('change', (e) => {
        if (e.target.checkVisibility()) {
          const source = sourceSelector(e.target);
          if (source !== lastSource) {
            sampleRUM('fill', { source });
            lastSource = source;
          }
        }
      });
      form.addEventListener('focusin', (e) => {
        if (['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'].includes(e.target.tagName)
          || e.target.getAttribute('contenteditable') === 'true') {
          sampleRUM('click', { source: sourceSelector(e.target) });
        }
      });
    });
  }
  function addObserver(ck, fn, block) {
    return DEFAULT_TRACKING_EVENTS.includes(ck) && fn(block);
  }
  function blocksMCB(mutations) {
    mutations
      .filter((m) => m.type === 'attributes' && m.attributeName === 'data-block-status')
      .filter((m) => m.target.dataset.blockStatus === 'loaded')
      .forEach((m) => {
        addObserver('form', addFormTracking, m.target);
        addObserver('viewblock', addViewBlockTracking, m.target);
      });
  }
  function mediaMCB(mutations) {
    mutations
      .forEach((m) => {
        addObserver('viewmedia', addViewMediaTracking, m.target);
      });
  }
  function addTrackingFromConfig() {
    document.addEventListener('click', (event) => {
      sampleRUM('click', { target: targetSelector(event.target), source: sourceSelector(event.target) });
    });
    addCWVTracking();
    addFormTracking(window.document.body);
    addNavigationTracking();
    addLoadResourceTracking();
    addUTMParametersTracking(sampleRUM);
    addViewBlockTracking(window.document.body);
    addViewMediaTracking(window.document.body);
    addCookieConsentTracking(sampleRUM);
    addAdsParametersTracking(sampleRUM);
    addEmailParameterTracking(sampleRUM);
    fflags.enabled('language', () => {
      const target = navigator.language;
      const source = document.documentElement.lang;
      sampleRUM('language', { source, target });
    });
  }
  function initEnhancer() {
    try {
      if (sampleRUM) {
        addTrackingFromConfig();
        window.hlx.rum.collector = trackCheckpoint;
        processQueue();
      }
    } catch (error) {
    }
  }
  initEnhancer();

})();
