/* 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/. */

/* eslint-env mozilla/remote-page */

import LockwiseCard from "./lockwise-card.mjs";
import MonitorCard from "./monitor-card.mjs";
import ProxyCard from "./proxy-card.mjs";
import VPNCard from "./vpn-card.mjs";

let cbCategory = RPMGetStringPref("browser.contentblocking.category");
document.sendTelemetryEvent = (action, object, value = "") => {
  // eslint-disable-next-line no-undef
  RPMRecordTelemetryEvent("security.ui.protections", action, object, value, {
    category: cbCategory,
  });
};

let { protocol, pathname, searchParams } = new URL(document.location);

let searchParamsChanged = false;
if (searchParams.has("entrypoint")) {
  RPMSendAsyncMessage("RecordEntryPoint", {
    entrypoint: searchParams.get("entrypoint"),
  });
  // Remove this parameter from the URL (after recording above) to make it
  // cleaner for bookmarking and switch-to-tab and so that bookmarked values
  // don't skew telemetry.
  searchParams.delete("entrypoint");
  searchParamsChanged = true;
}

document.addEventListener("DOMContentLoaded", e => {
  if (searchParamsChanged) {
    let newURL = protocol + pathname;
    let params = searchParams.toString();
    if (params) {
      newURL += "?" + params;
    }
    window.location.replace(newURL);
    return;
  }

  RPMSendQuery("FetchEntryPoint", {}).then(entrypoint => {
    // Send telemetry on arriving on this page
    document.sendTelemetryEvent("show", "protection_report", entrypoint);
  });

  // We need to send the close telemetry before unload while we still have a connection to RPM.
  window.addEventListener("beforeunload", () => {
    document.sendTelemetryEvent("close", "protection_report");
  });

  let todayInMs = Date.now();
  let weekAgoInMs = todayInMs - 6 * 24 * 60 * 60 * 1000;

  let dataTypes = [
    "cryptominer",
    "fingerprinter",
    "tracker",
    "cookie",
    "social",
  ];

  let manageProtectionsLink = document.getElementById("protection-settings");
  let manageProtections = document.getElementById("manage-protections");
  let protectionSettingsEvtHandler = evt => {
    if (evt.keyCode == evt.DOM_VK_RETURN || evt.type == "click") {
      RPMSendAsyncMessage("OpenContentBlockingPreferences");
      if (evt.target.id == "protection-settings") {
        document.sendTelemetryEvent(
          "click",
          "settings_link",
          "header-settings"
        );
      } else if (evt.target.id == "manage-protections") {
        document.sendTelemetryEvent(
          "click",
          "settings_link",
          "custom-card-settings"
        );
      }
    }
  };
  manageProtectionsLink.addEventListener("click", protectionSettingsEvtHandler);
  manageProtectionsLink.addEventListener(
    "keypress",
    protectionSettingsEvtHandler
  );
  manageProtections.addEventListener("click", protectionSettingsEvtHandler);
  manageProtections.addEventListener("keypress", protectionSettingsEvtHandler);

  let legend = document.getElementById("legend");
  legend.style.gridTemplateAreas =
    "'social cookie tracker fingerprinter cryptominer'";

  let createGraph = data => {
    let graph = document.getElementById("graph");
    let summary = document.getElementById("graph-total-summary");
    let weekSummary = document.getElementById("graph-week-summary");

    // User is in private mode, show no data on the graph
    if (data.isPrivate) {
      graph.classList.add("private-window");
    } else {
      let earliestDate = data.earliestDate || Date.now();
      summary.setAttribute(
        "data-l10n-args",
        JSON.stringify({ count: data.sumEvents, earliestDate })
      );
      summary.setAttribute("data-l10n-id", "graph-total-tracker-summary");
    }

    // Set a default top size for the height of the graph bars so that small
    // numbers don't fill the whole graph.
    let largest = 100;
    if (largest < data.largest) {
      largest = data.largest;
    }
    let weekCount = 0;
    let weekTypeCounts = {
      social: 0,
      cookie: 0,
      tracker: 0,
      fingerprinter: 0,
      cryptominer: 0,
    };

    // For accessibility clients, we turn the graph into a fake table with annotated text.
    // We use WAI-ARIA roles, properties, and states to mark up the table, rows and cells.
    // Each day becomes one row in the table.
    // Each row contains the day, total, and then one cell for each bar that we display.
    // At most, a row can contain seven cells.
    // But we need to caclulate the actual number of the most cells in a row to give accurate information.
    let maxColumnCount = 0;
    let date = new Date();
    for (let i = 0; i <= 6; i++) {
      let dateString = date.toISOString().split("T")[0];
      let ariaOwnsString = ""; // Get the row's colummns in order
      let currentColumnCount = 0;
      let bar = document.createElement("div");
      bar.className = "graph-bar";
      bar.setAttribute("role", "row");
      let innerBar = document.createElement("div");
      innerBar.className = "graph-wrapper-bar";
      if (data[dateString]) {
        let content = data[dateString];
        let count = document.createElement("div");
        count.className = "bar-count";
        count.id = "count" + i;
        count.setAttribute("role", "cell");
        count.textContent = content.total;
        setTimeout(() => {
          count.classList.add("animate");
        }, 400);
        bar.appendChild(count);
        ariaOwnsString = count.id;
        currentColumnCount += 1;
        let barHeight = (content.total / largest) * 100;
        weekCount += content.total;
        // Add a short timeout to allow the elements to be added to the dom before triggering an animation.
        setTimeout(() => {
          bar.style.height = `${barHeight}%`;
        }, 20);
        for (let type of dataTypes) {
          if (content[type]) {
            let dataHeight = (content[type] / content.total) * 100;
            // Since we are dealing with non-visual content, screen readers need a parent container to get the text
            let cellSpan = document.createElement("span");
            cellSpan.id = type + i;
            cellSpan.setAttribute("role", "cell");
            let div = document.createElement("div");
            div.className = `${type}-bar inner-bar`;
            div.setAttribute("role", "img");
            div.setAttribute("data-type", type);
            div.style.height = `${dataHeight}%`;
            div.setAttribute(
              "data-l10n-args",
              JSON.stringify({ count: content[type], percentage: dataHeight })
            );
            div.setAttribute("data-l10n-id", `bar-tooltip-${type}`);
            weekTypeCounts[type] += content[type];
            cellSpan.appendChild(div);
            innerBar.appendChild(cellSpan);
            ariaOwnsString = ariaOwnsString + " " + cellSpan.id;
            currentColumnCount += 1;
          }
        }
        if (currentColumnCount > maxColumnCount) {
          // The current row has more than any previous rows
          maxColumnCount = currentColumnCount;
        }
      } else {
        // There were no content blocking events on this day.
        bar.classList.add("empty");
      }
      bar.appendChild(innerBar);
      graph.prepend(bar);

      if (data.isPrivate) {
        weekSummary.setAttribute(
          "data-l10n-id",
          "graph-week-summary-private-window"
        );
      } else {
        weekSummary.setAttribute(
          "data-l10n-args",
          JSON.stringify({ count: weekCount })
        );
        weekSummary.setAttribute("data-l10n-id", "graph-week-summary");
      }

      let label = document.createElement("span");
      label.className = "column-label";
      // While the graphs fill up from the right, the days fill up from the left, so match the IDs
      label.id = "day" + (6 - i);
      label.setAttribute("role", "rowheader");
      if (i == 6) {
        label.setAttribute("data-l10n-id", "graph-today");
      } else {
        label.textContent = data.weekdays[(i + 1 + new Date().getDay()) % 7];
      }
      graph.append(label);
      // Make the day the first column in a row, making it the row header.
      bar.setAttribute("aria-owns", "day" + i + " " + ariaOwnsString);
      date.setDate(date.getDate() - 1);
    }
    maxColumnCount += 1; // Add the day column in the fake table
    graph.setAttribute("aria-colCount", maxColumnCount);
    // Set the total number of each type of tracker on the tabs as well as their
    // "Learn More" links
    for (let type of dataTypes) {
      document.querySelector(`label[data-type=${type}] span`).textContent =
        weekTypeCounts[type];
      const learnMoreLink = document.getElementById(`${type}-link`);
      learnMoreLink.href = RPMGetFormatURLPref(
        `browser.contentblocking.report.${type}.url`
      );
      learnMoreLink.addEventListener("click", () => {
        document.sendTelemetryEvent("click", "trackers_about_link", type);
      });
    }

    let blockingCookies =
      RPMGetIntPref("network.cookie.cookieBehavior", 0) != 0;
    let cryptominingEnabled = RPMGetBoolPref(
      "privacy.trackingprotection.cryptomining.enabled",
      false
    );
    let fingerprintingEnabled = RPMGetBoolPref(
      "privacy.trackingprotection.fingerprinting.enabled",
      false
    );
    let tpEnabled = RPMGetBoolPref("privacy.trackingprotection.enabled", false);
    let socialTracking = RPMGetBoolPref(
      "privacy.trackingprotection.socialtracking.enabled",
      false
    );
    let socialCookies = RPMGetBoolPref(
      "privacy.socialtracking.block_cookies.enabled",
      false
    );
    let socialEnabled =
      socialCookies && (blockingCookies || (tpEnabled && socialTracking));
    let notBlocking =
      !blockingCookies &&
      !cryptominingEnabled &&
      !fingerprintingEnabled &&
      !tpEnabled &&
      !socialEnabled;

    // User has turned off all blocking, show a different card.
    if (notBlocking) {
      document
        .getElementById("etp-card-content")
        .setAttribute(
          "data-l10n-id",
          "protection-report-etp-card-content-custom-not-blocking"
        );
      document
        .querySelector(".etp-card .card-title")
        .setAttribute("data-l10n-id", "etp-card-title-custom-not-blocking");
      document
        .getElementById("report-summary")
        .setAttribute("data-l10n-id", "protection-report-page-summary");
      document.querySelector(".etp-card").classList.add("custom-not-blocking");

      // Hide the link to settings from the header, so we are not showing two links.
      manageProtectionsLink.style.display = "none";
    } else {
      // Hide each type of tab if blocking of that type is off.
      if (!tpEnabled) {
        legend.style.gridTemplateAreas = legend.style.gridTemplateAreas.replace(
          "tracker",
          ""
        );
        let radio = document.getElementById("tab-tracker");
        radio.setAttribute("disabled", true);
        document.querySelector("#tab-tracker ~ label").style.display = "none";
      }
      if (!socialEnabled) {
        legend.style.gridTemplateAreas = legend.style.gridTemplateAreas.replace(
          "social",
          ""
        );
        let radio = document.getElementById("tab-social");
        radio.setAttribute("disabled", true);
        document.querySelector("#tab-social ~ label").style.display = "none";
      }
      if (!blockingCookies) {
        legend.style.gridTemplateAreas = legend.style.gridTemplateAreas.replace(
          "cookie",
          ""
        );
        let radio = document.getElementById("tab-cookie");
        radio.setAttribute("disabled", true);
        document.querySelector("#tab-cookie ~ label").style.display = "none";
      }
      if (!cryptominingEnabled) {
        legend.style.gridTemplateAreas = legend.style.gridTemplateAreas.replace(
          "cryptominer",
          ""
        );
        let radio = document.getElementById("tab-cryptominer");
        radio.setAttribute("disabled", true);
        document.querySelector("#tab-cryptominer ~ label").style.display =
          "none";
      }
      if (!fingerprintingEnabled) {
        legend.style.gridTemplateAreas = legend.style.gridTemplateAreas.replace(
          "fingerprinter",
          ""
        );
        let radio = document.getElementById("tab-fingerprinter");
        radio.setAttribute("disabled", true);
        document.querySelector("#tab-fingerprinter ~ label").style.display =
          "none";
      }

      let firstRadio = document.querySelector("input:enabled");
      // There will be no radio options if we are showing the
      firstRadio.checked = true;
      document.body.setAttribute("focuseddatatype", firstRadio.dataset.type);

      addListeners();
    }
  };

  let addListeners = () => {
    let wrapper = document.querySelector(".body-wrapper");
    let triggerTabClick = ev => {
      if (ev.originalTarget.dataset.type) {
        document.getElementById(`tab-${ev.target.dataset.type}`).click();
      }
    };

    let triggerTabFocus = ev => {
      if (ev.originalTarget.dataset) {
        wrapper.classList.add("hover-" + ev.originalTarget.dataset.type);
      }
    };

    let triggerTabBlur = ev => {
      if (ev.originalTarget.dataset) {
        wrapper.classList.remove("hover-" + ev.originalTarget.dataset.type);
      }
    };
    wrapper.addEventListener("mouseout", triggerTabBlur);
    wrapper.addEventListener("mouseover", triggerTabFocus);
    wrapper.addEventListener("click", triggerTabClick);

    // Change the class on the body to change the color variable.
    let radios = document.querySelectorAll("#legend input");
    for (let radio of radios) {
      radio.addEventListener("change", ev => {
        document.body.setAttribute("focuseddatatype", ev.target.dataset.type);
      });
      radio.addEventListener("focus", ev => {
        wrapper.classList.add("hover-" + ev.originalTarget.dataset.type);
        document.body.setAttribute("focuseddatatype", ev.target.dataset.type);
      });
      radio.addEventListener("blur", ev => {
        wrapper.classList.remove("hover-" + ev.originalTarget.dataset.type);
      });
    }
  };

  RPMSendQuery("FetchContentBlockingEvents", {
    from: weekAgoInMs,
    to: todayInMs,
  }).then(createGraph);

  let exitIcon = document.querySelector("#mobile-hanger .exit-icon");
  // hide the mobile promotion and keep hidden with a pref.
  exitIcon.addEventListener("click", () => {
    RPMSetBoolPref("browser.contentblocking.report.show_mobile_app", false);
    document.getElementById("mobile-hanger").classList.add("hidden");
  });

  let androidMobileAppLink = document.getElementById(
    "android-mobile-inline-link"
  );
  androidMobileAppLink.href = RPMGetStringPref(
    "browser.contentblocking.report.mobile-android.url"
  );
  androidMobileAppLink.addEventListener("click", () => {
    document.sendTelemetryEvent("click", "mobile_app_link", "android");
  });
  let iosMobileAppLink = document.getElementById("ios-mobile-inline-link");
  iosMobileAppLink.href = RPMGetStringPref(
    "browser.contentblocking.report.mobile-ios.url"
  );
  iosMobileAppLink.addEventListener("click", () => {
    document.sendTelemetryEvent("click", "mobile_app_link", "ios");
  });

  let lockwiseEnabled = RPMGetBoolPref(
    "browser.contentblocking.report.lockwise.enabled",
    true
  );

  let lockwiseCard;
  if (lockwiseEnabled) {
    const lockwiseUI = document.querySelector(".lockwise-card");
    lockwiseUI.classList.remove("hidden");
    lockwiseUI.classList.add("loading");

    lockwiseCard = new LockwiseCard(document);
    lockwiseCard.init();
  }

  RPMSendQuery("FetchUserLoginsData", {}).then(data => {
    if (lockwiseCard) {
      // Once data for the user is retrieved, display the lockwise card.
      lockwiseCard.buildContent(data);
    }

    if (
      RPMGetBoolPref("browser.contentblocking.report.show_mobile_app") &&
      !data.mobileDeviceConnected
    ) {
      document
        .getElementById("mobile-hanger")
        .classList.toggle("hidden", false);
    }
  });

  // For tests
  const lockwiseUI = document.querySelector(".lockwise-card");
  lockwiseUI.dataset.enabled = lockwiseEnabled;

  let monitorEnabled = RPMGetBoolPref(
    "browser.contentblocking.report.monitor.enabled",
    true
  );
  if (monitorEnabled) {
    // Show the Monitor card.
    const monitorUI = document.querySelector(".card.monitor-card.hidden");
    monitorUI.classList.remove("hidden");
    monitorUI.classList.add("loading");

    const monitorCard = new MonitorCard(document);
    monitorCard.init();
  }

  // For tests
  const monitorUI = document.querySelector(".monitor-card");
  monitorUI.dataset.enabled = monitorEnabled;

  const proxyEnabled = RPMGetBoolPref(
    "browser.contentblocking.report.proxy.enabled",
    true
  );

  if (proxyEnabled) {
    const proxyCard = new ProxyCard(document);
    proxyCard.init();
  }

  // For tests
  const proxyUI = document.querySelector(".proxy-card");
  proxyUI.dataset.enabled = proxyEnabled;

  const VPNEnabled = RPMGetBoolPref("browser.vpn_promo.enabled", true);
  if (VPNEnabled) {
    const vpnCard = new VPNCard(document);
    vpnCard.init();
  }
  // For tests
  const vpnUI = document.querySelector(".vpn-card");
  vpnUI.dataset.enabled = VPNEnabled;
});