(function () {
  const UserTrackingSDK = {
    NOT_YET: "NOT_YET",
    IS_VALID_OK: "IS_VALID_OK",
    IS_VALID_FAIL: "IS_VALID_FAIL",
    config: {
      apiEndpoint: "https://api.altn.team/api/v0.0/sdk",
      storageKey: "overpath_uuid",
      intentTime: "10000",
      intervalId: null,
      isValidSDK: this.NOT_YET,
    },
    initialized: false,
    isSessionReset: false,

    init: function (apiKey, customConfig = {}) {
      if (this.initialized) {
        return;
      }

      if (!apiKey) {
        throw new Error("API Key is required to initialize the SDK.");
      }
      this.config = { ...this.config, ...customConfig, apiKey };

      this.ensurebrowserId();
      this.ensureSessionId();

      this.setupUrlChangeListener();

      this.initialized = true;
    },

    setupUrlChangeListener: function () {
      let isPageVisible = true;
      let lastSentTimestamp = 0;
      let lastSentEventType = null;
      let sessionStartTime = Date.now();

      const EventType = {
        PERSISTED: "PERSISTED",
        PUSHSTATE: "PUSHSTATE",
        POPSTATE: "POPSTATE",
        PAGESHOW: "PAGESHOW",
        VISIBLE: "VISIBLE",
        HIDDEN: "HIDDEN",
        CLOSE: "CLOSE",
        INTERVAL: "INTERVAL",
      };

      const getDynamicInterval = () => {
        const elapsedTime = Date.now() - sessionStartTime;
        const elapsedSeconds = elapsedTime / 1000;

        if (elapsedSeconds >= 200) {
          return 1000000;
        } else if (elapsedSeconds >= 50) {
          return 30000;
        } else {
          return parseInt(this.config.intentTime);
        }
      };

      const updateInterval = () => {
        if (this.intervalId) {
          clearInterval(this.intervalId);
        }

        const newInterval = getDynamicInterval();
        this.intervalId = setInterval(() => {
          sendPageVisitData(EventType.INTERVAL);
          updateInterval();
        }, newInterval);
      };

      const sendPageVisitData = (eventType = EventType.INTERVAL) => {
        const now = Date.now();
        const deduplicationWindow = 500;
        if (
          eventType === lastSentEventType &&
          now - lastSentTimestamp < deduplicationWindow
        ) {
          return;
        }

        lastSentEventType = eventType;
        lastSentTimestamp = now;
        if (!isPageVisible) return;

        if (this.config.isValidSDK === this.IS_VALID_FAIL) return;

        const browserId = this.ensurebrowserId();
        const sessionId = this.ensureSessionId();
        const currentUrl = window.location.href;
        if (currentUrl.includes("traffic_type=internal")) {
          return;
        }

        const referrer = document.referrer;
        const userAgent = navigator.userAgent;
        const language = navigator.language;
        const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;

        const data = {
          data: {
            apiKey: this.config.apiKey,
            browserId,
            sessionId,
            url: currentUrl,
            referrer,
            userAgent,
            language,
            timeZone,
            timestamp: Math.floor(Date.now() / 1000),
            eventType: eventType,
          },
        };

        if (eventType == EventType.CLOSE) {
          var params = new Blob([JSON.stringify(data)], {
            type: "application/json",
          });
          navigator.sendBeacon(this.config.apiEndpoint + "/track", params);
          return;
        }

        fetch(this.config.apiEndpoint + "/track", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(data),
        })
          .then((response) => {
            return response.json();
          })
          .then((responseBody) => {
            if (responseBody.status !== 200) {
              this.config.isValidSDK = this.IS_VALID_FAIL;
            } else {
              this.config.isValidSDK = this.IS_VALID_OK;
            }
          })
          .catch((error) => error);
      };

      document.addEventListener("visibilitychange", () => {
        if (!isPageVisible) {
          sendPageVisitData(EventType.VISIBLE);
        } else {
          sendPageVisitData(EventType.HIDDEN);
        }
        isPageVisible = !document.hidden;
      });

      window.addEventListener("beforeunload", (event) => {
        sendPageVisitData(EventType.CLOSE);
      });

      window.addEventListener("pageshow", (event) => {
        if (event.persisted) {
          sendPageVisitData(EventType.PERSISTED);
          return;
        }
        if (
          !this.isSessionReset &&
          this.getPreviousUrl() == window.location.href
        ) {
          return;
        } else {
          this.config.isValidSDK = this.NOT_YET;
          sendPageVisitData(EventType.PAGESHOW);
        }
      });
      this.config.isValidSDK = this.NOT_YET;
      sendPageVisitData(EventType.PAGESHOW);
      window.addEventListener("popstate", () => {
        this.config.isValidSDK = this.NOT_YET;
        sendPageVisitData(EventType.POPSTATE);
      });

      const originalPushState = history.pushState.bind(history);
      const originalReplaceState = history.replaceState.bind(history);
      const sdk = this;

      history.pushState = function () {
        originalPushState.apply(this, arguments);
        sdk.config.isValidSDK = sdk.NOT_YET;
        sendPageVisitData(EventType.PUSHSTATE);
      };

      if (this.intervalId) clearInterval(this.intervalId);

      updateInterval();
    },

    ensurebrowserId: function () {
      let browserId = localStorage.getItem(this.config.storageKey);

      if (!browserId) {
        browserId = this.generateUUID();
        localStorage.setItem(this.config.storageKey, browserId);
      }

      return browserId;
    },

    ensurePreviousUrl: function () {
      sessionStorage.setItem("overpath_previous_url", window.location.href);
    },

    getPreviousUrl: function () {
      let previousUrl = sessionStorage.getItem("overpath_previous_url");
      return previousUrl;
    },

    ensureSessionId: function () {
      let sessionId = sessionStorage.getItem(this.config.storageKey);

      if (!sessionId) {
        this.isSessionReset = true;
        sessionId = this.generateUUID();
        sessionStorage.setItem(this.config.storageKey, sessionId);
      }

      return sessionId;
    },

    resetSessionId: function () {
      const newSessionId = this.generateUUID();
      sessionStorage.setItem(this.config.storageKey, newSessionId);
    },

    generateUUID: function () {
      return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
        /[xy]/g,
        function (c) {
          const r = (Math.random() * 16) | 0;
          const v = c === "x" ? r : (r & 0x3) | 0x8;
          return v.toString(16);
        }
      );
    },
  };

  window.UserTrackingSDK = UserTrackingSDK;
})();
