"use strict";
const isChartZoomed = "ow2-chart-custom-zoom"; // true/false
const isChartZoomScroll = "ow2-chart-custom-zoom-scroll"; // true/false
const isCustomDateRange = "ow2-chart-custom-daterange"; // true/false
const timeRangeKey = "ow2-chart-time-range"; // 30d
const startDayKey = "ow2-chart-start-day"; // September 3, 2022
const endDayKey = "ow2-chart-end-day"; // October 3, 2022
const startDateTimeKey = "ow2-chart-start-datetime"; // 2022-09-03 00:00:00
const endDateTimeKey = "ow2-chart-end-datetime"; // 2022-09-03 00:00:00
const pickerChosenLabelKey = "ow2-chart-picker-label"; // 2022-09-03 00:00:00
const zoomtimeRangeKey = "ow2-chart-zoom-time-range"; // 30d
const zoomStartDayKey = "ow2-chart-zoom-start-day"; // September 3, 2022
const zoomEndDayKey = "ow2-chart-zoom-end-day"; // October 3, 2022
const zoomStartDateTimeKey = "ow2-chart-zoom-start-datetime"; // 2022-09-03 00:00:00
const zoomEndDateTimeKey = "ow2-chart-zoom-end-datetime"; // 2022-09-03 00:00:00
const zoomChartIdKey = "ow2-chart-zoom-id"; // true/false

django.jQuery(
  (function ($) {
    $(document).ready(function () {
      var pickerStart,
        pickerEnd,
        pickerDays,
        pickerChosenLabel,
        end = moment();
      var range =
        localStorage.getItem(timeRangeKey) ||
        $("#monitoring-timeseries-default-time").data("value");
      var start =
        localStorage.getItem(isCustomDateRange) === "true"
          ? moment()
          : moment().subtract(range.split("d")[0], "days");

      // Initialize date range picker labels
      var last1DayLabel = gettext("Last 1 Day");
      var last3DaysLabel = gettext("Last 3 Days");
      var last7DaysLabel = gettext("Last 7 Days");
      var last30DaysLabel = gettext("Last 30 Days");
      var last365DaysLabel = gettext("Last 365 Days");
      var customDateRangeLabel = gettext("Custom Range");

      // Add label to daterangepicker widget
      function addDateRangePickerLabel(startDate, endDate) {
        $("#daterangepicker-widget span").html(startDate + " - " + endDate);
      }

      function initDateRangePickerWidget(start, end) {
        addDateRangePickerLabel(
          start.format("MMMM D, YYYY"),
          end.format("MMMM D, YYYY"),
        );
        $(`[data-range-key='${last1DayLabel}']`).attr("data-time", "1d");
        $(`[data-range-key='${last3DaysLabel}']`).attr("data-time", "3d");
        $(`[data-range-key='${last7DaysLabel}']`).attr("data-time", "7d");
        $(`[data-range-key='${last30DaysLabel}']`).attr("data-time", "30d");
        $(`[data-range-key='${last365DaysLabel}']`).attr("data-time", "365d");
        $(`[data-range-key='${customDateRangeLabel}']`).attr(
          "data-time",
          customDateRangeLabel,
        );
      }

      $("#daterangepicker-widget").daterangepicker(
        {
          startDate: start,
          endDate: end,
          maxDate: moment(),
          maxSpan: {
            year: 1,
          },
          locale: {
            applyLabel: gettext("Apply"),
            cancelLabel: gettext("Cancel"),
            customRangeLabel: gettext(customDateRangeLabel),
          },
          ranges: {
            [`${last1DayLabel}`]: [moment().subtract(1, "days"), moment()],
            [`${last3DaysLabel}`]: [moment().subtract(3, "days"), moment()],
            [`${last7DaysLabel}`]: [moment().subtract(7, "days"), moment()],
            [`${last30DaysLabel}`]: [moment().subtract(30, "days"), moment()],
            [`${last365DaysLabel}`]: [moment().subtract(365, "days"), moment()],
          },
        },
        initDateRangePickerWidget,
      );
      initDateRangePickerWidget(start, end);

      function setDateRangePickerWidget(pickerStartDate, pickerEndDate) {
        addDateRangePickerLabel(
          pickerStartDate.format("MMMM D, YYYY"),
          pickerEndDate.format("MMMM D, YYYY"),
        );
        $("#daterangepicker-widget")
          .data("daterangepicker")
          .setStartDate(
            moment(pickerStartDate.format("MMMM D, YYYY")).format("MM/DD/YYYY"),
          );
        $("#daterangepicker-widget")
          .data("daterangepicker")
          .setEndDate(
            moment(pickerEndDate.format("MMMM D, YYYY")).format("MM/DD/YYYY"),
          );
      }
      function isMonitoringChartsLocation() {
        // If active monitoring charts location is not #ow-chart-container and not admin
        return (
          window.location.hash === "#ow-chart-container" ||
          window.location.pathname === "/admin/"
        );
      }

      function handleChartZoomChange(chartsContainers) {
        // Simply return if we are not at the monitoring chart location
        if (!isMonitoringChartsLocation()) {
          return;
        }
        // Handle chart zooming with custom dates
        var zoomCharts = document.getElementsByClassName(chartsContainers);
        // Set zoomChartId, required for scrolling after the zoom-in event
        $(".js-plotly-plot").on("click dblclick mouseover mouseout", function () {
          var zoomChartId = $(this).parent().prop("id");
          if (zoomChartId === "chart-0") {
            var activeChartsLocation = window.location.hash;
            zoomChartId =
              activeChartsLocation === "#ow-chart-container"
                ? "container"
                : "ow-chart-inner-container";
          }
          localStorage.setItem(zoomChartIdKey, zoomChartId);
        });
        for (var zoomChart of zoomCharts) {
          if (!zoomChart) {
            localStorage.setItem(isChartZoomed, false);
            localStorage.setItem(isCustomDateRange, false);
            return;
          }
          zoomChart.on("plotly_relayout", function (eventdata) {
            // jshint ignore:line
            var eventEnd = eventdata["xaxis.range[1]"];
            var eventStart = eventdata["xaxis.range[0]"];
            // Simply return if we are not at the monitoring chart location
            if (!isMonitoringChartsLocation()) {
              return;
            }
            // When the chart is zoomed out, then load charts with initial zoom level
            if (!eventEnd && !eventStart) {
              localStorage.setItem(isChartZoomed, false);
              localStorage.setItem(isCustomDateRange, false);
              // After zoomed out, it should scroll back initial zoom container
              localStorage.setItem(isChartZoomScroll, true);
              var daysBeforeZoom = localStorage.getItem(timeRangeKey);
              // Set custom date range labels & select custom date ranges for the widget
              var initialStartLabel =
                localStorage.getItem(startDayKey) || moment().format("MMMM D, YYYY");
              var initialEndLabel =
                localStorage.getItem(endDayKey) || moment().format("MMMM D, YYYY");
              var initialStartDate = moment(initialStartLabel, "MMMM D, YYYY");
              var initialEndDate = moment(initialEndLabel, "MMMM D, YYYY");
              // Set date range picker widget labels
              setDateRangePickerWidget(initialStartDate, initialEndDate);
              // On zoom out, load all charts to their initial zoom level
              loadCharts(daysBeforeZoom, true);
              // refresh every 2.5 minutes
              clearInterval(window.owChartRefresh);
              window.owChartRefresh = setInterval(
                loadFetchedCharts,
                1000 * 60 * 2.5,
                daysBeforeZoom,
              );
              return;
            }
            // When the chart zoomed in,
            var pickerEndDate = moment(eventEnd);
            var pickerStartDate = moment(eventStart);
            var pickerDays = pickerEndDate.diff(pickerStartDate, "days") + "d";
            if (pickerDays === "0d") {
              pickerDays = "1d";
            }
            // Set custom date range values
            localStorage.setItem(
              zoomStartDateTimeKey,
              pickerStartDate.format("YYYY-MM-DD HH:mm:ss"),
            );
            localStorage.setItem(
              zoomEndDateTimeKey,
              pickerEndDate.format("YYYY-MM-DD HH:mm:ss"),
            );
            localStorage.setItem(
              zoomStartDayKey,
              pickerStartDate.format("MMMM D, YYYY"),
            );
            localStorage.setItem(zoomEndDayKey, pickerEndDate.format("MMMM D, YYYY"));
            localStorage.setItem(isChartZoomScroll, true);
            localStorage.setItem(isChartZoomed, true);
            localStorage.setItem(isCustomDateRange, true);
            localStorage.setItem(zoomtimeRangeKey, pickerDays);
            // Set date range picker widget labels
            setDateRangePickerWidget(pickerStartDate, pickerEndDate);
            // Now, load the charts with custom date ranges
            loadCharts(pickerDays, true);
            // refresh every 2.5 minutes
            clearInterval(window.owChartRefresh);
            window.owChartRefresh = setInterval(
              loadFetchedCharts,
              1000 * 60 * 2.5,
              pickerDays,
            );
          });
        }
      }

      function triggerZoomCharts(containerClassName) {
        handleChartZoomChange(containerClassName);
        const zoomChartContainer = document.getElementById(
          localStorage.getItem(zoomChartIdKey),
        );
        // If the chart zoom scrolling is active, then scroll to the zoomed chart container
        if (localStorage.getItem(isChartZoomScroll) === "true" && zoomChartContainer) {
          zoomChartContainer.scrollIntoView();
        }
      }
      var chartQuickLinks,
        chartContents = $("#ow-chart-contents"),
        fallback = $("#ow-chart-fallback"),
        defaultTimeRange =
          localStorage.getItem(timeRangeKey) ||
          $("#monitoring-timeseries-default-time").data("value"),
        apiUrl = $("#monitoring-timeseries-api-url").data("value"),
        baseUrl = `${apiUrl}?time=`,
        globalLoadingOverlay = $("#loading-overlay"),
        localLoadingOverlay = $("#chart-loading-overlay"),
        getChartFetchUrl = function (time) {
          var url = baseUrl + time;
          // pass pickerEndDate and pickerStartDate to url
          if (
            localStorage.getItem(isCustomDateRange) === "true" ||
            localStorage.getItem(pickerChosenLabelKey) === customDateRangeLabel
          ) {
            var startDate = localStorage.getItem(startDateTimeKey);
            var endDate = localStorage.getItem(endDateTimeKey);
            if (localStorage.getItem(isChartZoomed) === "true") {
              endDate = localStorage.getItem(zoomEndDateTimeKey);
              startDate = localStorage.getItem(zoomStartDateTimeKey);
            }
            // Ensure that the 'endDate' of zooming events
            // is never greater than the 'now' date time
            const now = moment().format("YYYY-MM-DD HH:mm:ss");
            const endDateTime = moment(endDate).format("YYYY-MM-DD HH:mm:ss");
            endDate = endDateTime > now ? now : endDateTime;
            url = `${apiUrl}?start=${startDate}&end=${endDate}`;
            var timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
            if (timezone) {
              url = `${url}&timezone=${timezone}`;
            }
          }
          if ($("#org-selector").val()) {
            var orgSlug = $("#org-selector").val();
            url = `${url}&organization_slug=${orgSlug}`;
          }
          return url;
        },
        createCharts = function (data) {
          $.each(data.charts, function (i, chart) {
            var htmlId = "chart-" + i,
              chartDiv = $("#" + htmlId),
              chartQuickLink = chartQuickLinks[chart.title];
            if (!chartDiv.length) {
              chartContents.append(
                '<div id="' +
                  htmlId +
                  '" class="ow-chart">' +
                  '<div class="js-plotly-plot"></div></div>',
              );
            }
            createChart(chart, data.x, htmlId, chart.title, chart.type, chartQuickLink);
          });
        },
        addOrganizationSelector = function (data) {
          var orgSelector = $("#org-selector");
          if (data.organizations === undefined) {
            return;
          }
          if (orgSelector.data("select2-id") === "org-selector") {
            return;
          }
          orgSelector.parent().show();
          orgSelector.select2({
            data: data.organizations,
            allowClear: true,
            placeholder: gettext("Organization Filter"),
          });
          orgSelector.show();
        },
        loadCharts = function (time, showLoading) {
          $.ajax(getChartFetchUrl(time), {
            dataType: "json",
            xhrFields: {
              withCredentials: true,
            },
            beforeSend: function () {
              chartContents.hide();
              chartContents.empty();
              fallback.hide();
              if (showLoading) {
                globalLoadingOverlay.show();
              }
              localLoadingOverlay.show();
            },
            success: function (data) {
              localLoadingOverlay.hide();
              if (data.charts.length) {
                chartContents.show();
              } else {
                fallback.show();
              }
              createCharts(data);
              addOrganizationSelector(data);
            },
            error: function (response) {
              var errorMessage = gettext(
                "Something went wrong while loading the charts",
              );
              if (response.responseJSON) {
                if (response.responseJSON.constructor === Array) {
                  errorMessage = errorMessage + ": " + response.responseJSON.join(" ");
                }
              }
              alert(errorMessage);
            },
            complete: function () {
              triggerZoomCharts("js-plotly-plot");
              localLoadingOverlay.fadeOut(200, function () {
                if (showLoading) {
                  globalLoadingOverlay.fadeOut(200);
                }
              });
            },
          });
        };
      try {
        chartQuickLinks = JSON.parse($("#monitoring-chart-quick-links").html());
      } catch (error) {
        chartQuickLinks = {};
      }

      window.triggerChartLoading = function () {
        // Charts load with the last set time range or default time range
        var range = localStorage.getItem(timeRangeKey) || defaultTimeRange;
        var startLabel =
          localStorage.getItem(startDayKey) || moment().format("MMMM D, YYYY");
        var endLabel =
          localStorage.getItem(endDayKey) || moment().format("MMMM D, YYYY");

        // Disable the zoom chart and scrolling when we refresh the page
        localStorage.setItem(isChartZoomScroll, false);
        localStorage.setItem(isChartZoomed, false);

        if (localStorage.getItem(isCustomDateRange) === "true") {
          // Add label to daterangepicker widget
          addDateRangePickerLabel(startLabel, endLabel);
          // Set last selected custom date after page reload
          var startDate = moment(startLabel, "MMMM D, YYYY");
          var endDate = moment(endLabel, "MMMM D, YYYY");
          $("#daterangepicker-widget")
            .data("daterangepicker")
            .setStartDate(moment(startDate).format("MM/DD/YYYY"));
          $("#daterangepicker-widget")
            .data("daterangepicker")
            .setEndDate(moment(endDate).format("MM/DD/YYYY"));
          // Then loads charts with custom ranges selected
          loadCharts(range, true);
        } else {
          endLabel = moment().format("MMMM D, YYYY");
          startLabel = moment()
            .subtract(range.split("d")[0], "days")
            .format("MMMM D, YYYY");
          // Add label to daterangepicker widget
          addDateRangePickerLabel(startLabel, endLabel);
          // Set last selected default dates after page reload
          $(".daterangepicker .ranges ul li[data-time=" + range + "]").trigger("click");
        }
      };
      // try adding the browser timezone to the querystring
      try {
        var timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
        if (timezone) {
          baseUrl = baseUrl.replace("time=", "timezone=" + timezone + "&time=");
        }
        // ignore failures (older browsers do not support this)
      } catch (e) {}

      // daterangepicker widget logic here
      $("#daterangepicker-widget").on("apply.daterangepicker", function (ev, picker) {
        pickerChosenLabel = picker.chosenLabel;
        pickerStart = moment(picker.startDate.format("YYYY-MM-DD HH:mm:ss"));
        pickerEnd = moment(picker.endDate.format("YYYY-MM-DD HH:mm:ss"));
        pickerDays = pickerEnd.diff(pickerStart, "days") + "d";
        // set date values required for daterangepicker labels
        localStorage.setItem(pickerChosenLabelKey, pickerChosenLabel);
        localStorage.setItem(
          startDateTimeKey,
          picker.startDate.format("YYYY-MM-DD HH:mm:ss"),
        );
        localStorage.setItem(
          endDateTimeKey,
          picker.endDate.format("YYYY-MM-DD HH:mm:ss"),
        );
        localStorage.setItem(startDayKey, pickerStart.format("MMMM D, YYYY"));
        localStorage.setItem(endDayKey, pickerEnd.format("MMMM D, YYYY"));
        localStorage.setItem(isChartZoomed, false);
        localStorage.setItem(isChartZoomScroll, false);
        localStorage.setItem(timeRangeKey, pickerDays);
        localStorage.setItem(isCustomDateRange, pickerChosenLabel === "Custom Range");
        loadCharts(pickerDays, true);
        // refresh charts every 2.5 minutes
        clearInterval(window.owChartRefresh);
        window.owChartRefresh = setInterval(
          loadFetchedCharts,
          1000 * 60 * 2.5,
          pickerDays,
        );
      });
      // bind export button
      $("#ow-chart-export").click(function () {
        var queryString,
          queryParams = { csv: 1 };
        queryParams.time = localStorage.getItem(timeRangeKey);
        // If custom or pickerChosenLabelKey is 'Custom Range', pass pickerEndDate and pickerStartDate to csv url
        if (
          localStorage.getItem(isCustomDateRange) === "true" ||
          localStorage.getItem(pickerChosenLabelKey) === customDateRangeLabel
        ) {
          queryParams.start = localStorage.getItem(startDateTimeKey);
          queryParams.end = localStorage.getItem(endDateTimeKey);
          if (localStorage.getItem(isChartZoomed) === "true") {
            queryParams.time = localStorage.getItem(zoomtimeRangeKey);
            queryParams.end = localStorage.getItem(zoomEndDateTimeKey);
            queryParams.start = localStorage.getItem(zoomStartDateTimeKey);
          }
          timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
          if (timezone) {
            queryParams.timezone = timezone;
          }
        }
        if ($("#org-selector").val()) {
          queryParams.organization_slug = $("#org-selector").val();
        }
        queryString = Object.keys(queryParams)
          .map(
            (key) =>
              `${encodeURIComponent(key)}=${encodeURIComponent(queryParams[key])}`,
          )
          .join("&");
        location.href = `${apiUrl}?${queryString}`;
      });
      // fetch chart data and replace the old charts with the new ones
      function loadFetchedCharts(time) {
        $.ajax(getChartFetchUrl(time), {
          dataType: "json",
          success: function (data) {
            if (data.charts.length) {
              createCharts(data);
              triggerZoomCharts("js-plotly-plot");
            }
          },
          error: function () {
            window.console.error("Unable to fetch chart data.");
          },
        });
      }

      $("#org-selector").change(function () {
        loadCharts(localStorage.getItem(timeRangeKey) || defaultTimeRange, true);
      });
    });
  })(django.jQuery),
);
