/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/**
 * Bug 2006036 - Site does not load on Firefox.
 *
 * They are doing something odd which appears to break Firefox on purpose.
 */

if (!window.chrome) {
  console.info(
    "The window environment is being altered for compatibility reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=2006036 for details."
  );

  delete window.InstallTrigger;
  delete window.mozInnerScreenX;
  delete window.mozInnerScreenY;
  delete window.MozConsentBanner;

  const nav = Object.getPrototypeOf(navigator);
  const vendor = Object.getOwnPropertyDescriptor(nav, "vendor");
  vendor.get = () => "Google Inc.";
  Object.defineProperty(nav, "vendor", vendor);

  const supports = Object.getOwnPropertyDescriptor(CSS, "supports");
  const oldSupports = supports.value;
  supports.value = function (query) {
    if (query.includes("moz-")) {
      return false;
    }
    return oldSupports.call(this, query);
  };
  Object.defineProperty(CSS, "supports", supports);

  function generateTimeStamp(base, factor = 10) {
    if (base) {
      // increase another timestamp by a little
      return (base + Math.random() * factor).toString().substr(0, 14);
    }
    const r = Math.random().toString();
    const d10 = `1${r.substr(5, 9)}`;
    const d3 = r.substr(2, 3);
    return parseFloat(`${d10}.${d3}`);
  }

  const startLoadTime = generateTimeStamp();
  const commitLoadTime = generateTimeStamp(startLoadTime);
  const firstPaintTime = generateTimeStamp(commitLoadTime);
  const finishDocumentLoadTime = generateTimeStamp(firstPaintTime);
  const finishLoadTime = generateTimeStamp(finishDocumentLoadTime);

  const csi = {
    onloadT: parseInt(finishDocumentLoadTime * 100),
    pageT: generateTimeStamp().toString().substr(-11),
    startE: parseInt(parseFloat(startLoadTime * 100)),
    tran: 10 + parseInt(4 + Math.random() * 4),
  };

  const loadTimes = {
    commitLoadTime,
    connectionInfo: "h3",
    finishDocumentLoadTime,
    finishLoadTime,
    firstPaintAfterLoadTime: 0,
    firstPaintTime,
    navigationType: "Other",
    npnNegotiatedProtocol: "h3",
    requestTime: startLoadTime,
    startLoadTime,
    wasAlternateProtocolAvailable: false,
    wasFetchedViaSpdy: true,
    wasNpnNegotiated: true,
  };

  window.chrome = {
    app: {
      InstallState: {
        DISABLED: "disabled",
        INSTALLED: "installed",
        NOT_INSTALLED: "not_installed",
      },
      RunningState: {
        CANNOT_RUN: "cannot_run",
        READY_TO_RUN: "ready_to_run",
        RUNNING: "running",
      },
      getDetails() {
        return null;
      },
      getIsInstalled() {
        return false;
      },
      installState() {
        return undefined;
      },
      isInstalled: false,
      runningState() {
        return window.chrome.app.InstallState.NOT_INSTALLED;
      },
    },
    csi() {
      return csi;
    },
    loadTimes() {
      return loadTimes;
    },
  };

  const ua = navigator.userAgent;
  const mobile = ua.includes("Android");

  // Very roughly matches Chromium's GetPlatformForUAMetadata()
  let platform = "Linux";
  if (mobile) {
    platform = "Android";
  } else if (navigator.platform.startsWith("Win")) {
    platform = "Windows";
  } else if (navigator.platform.startsWith("Mac")) {
    platform = "macOS";
  }

  const version = ua.match(/Chrome\/([0-9]+)/)[1];

  // These match Chrome's output as of version 126.
  const brands = [
    {
      brand: "Not/A)Brand",
      version: "8",
    },
    {
      brand: "Chromium",
      version,
    },
    {
      brand: "Google Chrome",
      version,
    },
  ];

  // Site checks the high-entropy platformVersion on Windows.
  const userAgentData = {
    brands,
    mobile,
    platform,
    getHighEntropyValues() {
      return Promise.resolve({
        brands,
        mobile,
        platform,
        platformVersion: "19.0.0",
      });
    },
  };

  Object.defineProperty(nav, "userAgentData", {
    get: () => userAgentData,
    set: () => {},
  });
}
