<template>
  <v-row v-if="formState.ready" v-resize="onResize">
    <gz-error :error-box-message="formState.errorBoxMessage"></gz-error>
    <v-col cols="12" sm="6" lg="4" xl="3">
      <v-select
        v-model="selectedTimePeriod"
        :items="selectLists.dateFilterTokens"
        item-text="name"
        item-value="id"
        append-outer-icon="$ayiSync"
        data-cy="selectedTimePeriod"
        @click:append-outer="getDataFromApi"
        @input="timePeriodChanged"
      ></v-select>
    </v-col>

    <v-tabs v-model="tab" @change="tabChanged">
      <v-tabs-slider></v-tabs-slider>
      <v-tab>{{ $ay.t("MetricCPUMemory") }}</v-tab>
      <v-tab>{{ $ay.t("Database") }}</v-tab>
      <v-tab>{{ $ay.t("MetricFileStorage") }}</v-tab>

      <v-tabs-items v-model="tab">
        <v-tab-item>
          <v-col cols="12">
            <gz-chart-line
              :chart-data="memAllChartData"
              :options="timeLineMMChartOptions"
              class="my-12"
            />
          </v-col>
          <v-col cols="12">
            <gz-chart-line
              :chart-data="cpuChartData"
              :options="timeLineMMChartOptions"
              class="my-12"
            />
          </v-col>
        </v-tab-item>
        <v-tab-item>
          <v-col cols="12">
            <gz-chart-line
              :chart-data="dbChartData"
              :options="timeLineDDChartOptions"
              class="my-12"
            />
          </v-col>
          <v-col cols="12" lg="10" xl="8">
            <gz-chart-bar-horizontal
              :chart-data="dbTopTablesChartData"
              :options="{
                responsive: true,
                scales: {
                  xAxes: [{ gridLines: { display: true } }],
                  yAxes: [{ gridLines: { display: false } }]
                }
              }"
              class="my-12"
            />
          </v-col>
        </v-tab-item>
        <v-tab-item>
          <v-col cols="12">
            <gz-chart-line
              :chart-data="fileSizeChartData"
              :options="timeLineDDChartOptions"
              class="my-12"
            />
          </v-col>
          <v-col cols="12">
            <gz-chart-line
              :chart-data="attachmentCountChartData"
              :options="timeLineDDChartOptions"
              class="my-12"
            />
          </v-col>
        </v-tab-item>
      </v-tabs-items>
    </v-tabs>
  </v-row>
</template>
<script>
//https://blog.hubspot.com/marketing/types-of-graphs-for-data-visualization
//https://medium.com/javascript-in-plain-english/exploring-chart-js-e3ba70b07aa4
import relativeDatefilterCalculator from "../api/relative-date-filter-calculator.js";
import Palette from "../api/palette";
const FORM_KEY = "ops-metrics";
const DEFAULT_POINT = {
  Radius: 5,
  HoverRadius: 12,
  HitRadius: 4
};

export default {
  data() {
    return {
      storage: { isnew: true },
      memcpu: { isnew: true },
      db: { isnew: true },
      timeLineDDChartOptions: {
        responsive: true,
        maintainAspectRatio: false,
        scales: {
          xAxes: [
            {
              type: "time",
              time: {
                unit: "day"
              },
              gridLines: {
                drawOnChartArea: false
              }
            }
          ],
          yAxes: [
            {
              gridLines: {
                drawOnChartArea: false
              },
              ticks: {
                beginAtZero: true
              }
            }
          ]
        }
      },
      timeLineMMChartOptions: {
        responsive: true,
        maintainAspectRatio: false,
        scales: {
          xAxes: [
            {
              type: "time",
              // time: {
              //   unit: "minute"
              // },
              gridLines: {
                drawOnChartArea: false
              }
            }
          ],
          yAxes: [
            {
              gridLines: {
                drawOnChartArea: false
              },
              ticks: {
                beginAtZero: true
              }
            }
          ]
        }
      },
      selectedTimePeriod: "*past7days*",
      selectLists: {
        dateFilterTokens: []
      },
      lastFetchBreakPoint: null,
      tab: 0,
      formState: {
        ready: false,
        loading: false,
        errorBoxMessage: null,
        appError: null,
        serverError: {}
      }
    };
  },
  computed: {
    cpuChartData() {
      return {
        datasets: [
          {
            label: "CPU %",
            borderColor: Palette.color.soft_sand,
            fill: false,
            pointRadius: DEFAULT_POINT.Radius,
            pointHoverRadius: DEFAULT_POINT.HoverRadius,
            pointHitRadius: DEFAULT_POINT.HitRadius,
            data: this.memcpu.cpu
          }
        ]
      };
    },
    dbChartData() {
      return {
        datasets: [
          {
            label: this.$ay.t("MetricDBSize"),
            borderColor: Palette.color.blue,
            fill: false,
            pointRadius: DEFAULT_POINT.Radius,
            pointHoverRadius: DEFAULT_POINT.HoverRadius,
            pointHitRadius: DEFAULT_POINT.HitRadius,
            data: this.db.totalSize
          }
        ]
      };
    },
    dbTopTablesChartData() {
      if (!this.db.topTables) {
        return { labels: [], datasets: [] };
      }
      return {
        //  These labels appear in the legend and in the tooltips when hovering different arcs
        labels: this.db.topTables.map(z => z.name),
        datasets: [
          {
            label: this.$ay.t("MetricTopTablesSize"),
            data: this.db.topTables.map(z => z.value),
            backgroundColor: Palette.getSoftPaletteArray(
              this.db.topTables ? this.db.topTables.length : 3
            ),
            minBarLength: 5
          }
        ]
      };
    },
    memAllChartData() {
      return {
        datasets: [
          {
            label: this.$ay.t("MetricAllocatedMemory"),
            borderColor: Palette.color.soft_brown_darker,
            fill: false,
            pointRadius: DEFAULT_POINT.Radius,
            pointHoverRadius: DEFAULT_POINT.HoverRadius,
            pointHitRadius: DEFAULT_POINT.HitRadius,
            data: this.memcpu.allocated
          },
          {
            label: this.$ay.t("MetricWorkingSet"),
            borderColor: Palette.color.soft_green,
            pointRadius: DEFAULT_POINT.Radius,
            pointHoverRadius: DEFAULT_POINT.HoverRadius,
            pointHitRadius: DEFAULT_POINT.HitRadius,
            fill: false,
            data: this.memcpu.workingSet
          },
          {
            label: this.$ay.t("MetricPrivateBytes"),
            borderColor: Palette.color.soft_deep_blue,
            fill: false,
            pointRadius: DEFAULT_POINT.Radius,
            pointHoverRadius: DEFAULT_POINT.HoverRadius,
            pointHitRadius: DEFAULT_POINT.HitRadius,
            data: this.memcpu.privateBytes
          }
        ]
      };
    },
    fileSizeChartData() {
      return {
        datasets: [
          {
            label: this.$ay.t("MetricAttachmentsMB"),
            borderColor: Palette.color.purple,
            fill: false,
            pointRadius: DEFAULT_POINT.Radius,
            pointHoverRadius: DEFAULT_POINT.HoverRadius,
            pointHitRadius: DEFAULT_POINT.HitRadius,
            data: this.storage.attachmentFileSize
          },
          {
            label: this.$ay.t("MetricBackupMB"),
            borderColor: Palette.color.orange,
            fill: false,
            pointRadius: DEFAULT_POINT.Radius,
            pointHoverRadius: DEFAULT_POINT.HoverRadius,
            pointHitRadius: DEFAULT_POINT.HitRadius,
            data: this.storage.utilityFileSize
          },
          {
            label: this.$ay.t("MetricAvailableDiskSpace"),
            borderColor: Palette.color.green,
            fill: false,
            pointRadius: DEFAULT_POINT.Radius,
            pointHoverRadius: DEFAULT_POINT.HoverRadius,
            pointHitRadius: DEFAULT_POINT.HitRadius,
            data: this.storage.attachmentFilesAvailableSpace
          }
        ]
      };
    },
    attachmentCountChartData() {
      return {
        datasets: [
          {
            label: this.$ay.t("MetricAttachmentsCount"),
            borderColor: Palette.color.blue,
            fill: true,
            pointRadius: DEFAULT_POINT.Radius,
            pointHoverRadius: DEFAULT_POINT.HoverRadius,
            pointHitRadius: DEFAULT_POINT.HitRadius,
            data: this.storage.attachmentFileCount
          }
        ]
      };
    }
  },
  async created() {
    const vm = this;
    try {
      await initForm(vm);
      window.$gz.eventBus.$on("menu-click", clickHandler);
      generateMenu(vm);
      await vm.getDataFromApi();
    } catch (err) {
      vm.formState.ready = true;
      window.$gz.errorHandler.handleFormError(err, vm);
    }
  },
  beforeDestroy() {
    window.$gz.eventBus.$off("menu-click", clickHandler);
  },

  methods: {
    onResize() {
      let breakPoint = "xl";
      if (window.innerWidth < 1904) {
        breakPoint = "lg";
      }
      if (window.innerWidth < 1264) {
        breakPoint = "md";
      }
      if (window.innerWidth < 960) {
        breakPoint = "sm";
      }
      if (window.innerWidth < 600) {
        breakPoint = "xs";
      }
      if (breakPoint != this.lastFetchBreakPoint) {
        this.getDataFromApi(breakPoint);
      }
    },
    timePeriodChanged: function() {
      this.getDataFromApi();
    },
    tabChanged: function() {
      const vm = this;
      if (vm[tabIndexToRoute(vm.tab)].isnew) {
        vm.getDataFromApi();
      }
    },
    async getDataFromApi(breakPoint) {
      const vm = this;
      if (vm.formState.loading) {
        return;
      }
      const filterDates = relativeDatefilterCalculator.tokenToDates(
        vm.selectedTimePeriod
      );
      vm.formState.loading = true;
      if (breakPoint == null) {
        breakPoint = vm.$vuetify.breakpoint.name;
      }
      //##########################################################################################################################################
      //Visually, 200 points max looks best on full screen widths and 40 on galaxy s9 minimum standard
      //there is no relevant loss of fidelity with this downsampling
      let max = 200;
      //https://vuetifyjs.com/en/customization/breakpoints/#breakpoint-service-object
      //Note: used geometric progression of 1.5 for this
      //40*1.5=60, 60*1.5=90 etc etc etc
      //wanted it to fit between 40 at lowest end and 200 at highest end
      switch (breakPoint) {
        case "xs":
          max = 40;
          break;
        case "sm":
          max = 60;
          break;
        case "md":
          max = 90;
          break;
        case "lg":
          max = 135;
          break;
        case "xl":
          max = 200;
          break;
        default:
          max = 200;
      }
      const url =
        "server-metric/" +
        tabIndexToRoute(vm.tab) +
        "?maxRecords=" +
        max +
        "&tsStart=" +
        filterDates.after +
        "&tsEnd=" +
        filterDates.before;
      window.$gz.form.deleteAllErrorBoxErrors(vm);
      try {
        const res = await window.$gz.api.get(url);
        if (res.error) {
          if (res.error.code == "2010") {
            window.$gz.form.handleObjectNotFound(vm);
          }
          vm.formState.serverError = res.error;
          window.$gz.form.setErrorBoxErrors(vm);
        } else {
          vm[tabIndexToRoute(vm.tab)] = res.data;
          vm.lastFetchBreakPoint = breakPoint;
          window.$gz.form.setFormState({
            vm: vm,
            dirty: false,
            valid: true,
            loading: false
          });
          vm.formState.ready = true;
        }
      } catch (error) {
        window.$gz.form.setFormState({
          vm: vm,
          loading: false
        });
        window.$gz.errorHandler.handleFormError(error, vm);
      }
    }
  }
};

//////////////////////
//
//
function tabIndexToRoute(tabIndex) {
  switch (tabIndex) {
    case 0:
      return "memcpu";

    case 1:
      return "db";

    case 2:
      return "storage";
  }
}
//////////////////////
//
//
function generateMenu() {
  const menuOptions = {
    isMain: true,
    icon: "$ayiFileMedicalAlt",
    title: "ServerMetrics",
    helpUrl: "ops-metrics",
    formData: {
      ayaType: window.$gz.type.ServerMetrics
    },
    menuItems: []
  };
  window.$gz.eventBus.$emit("menu-change", menuOptions);
}

/////////////////////////////
//
//
function clickHandler(menuItem) {
  if (!menuItem) {
    return;
  }
  const m = window.$gz.menu.parseMenuItem(menuItem);
  if (m.owner == FORM_KEY && !m.disabled) {
    switch (m.key) {
      default:
        window.$gz.eventBus.$emit(
          "notify-warning",
          FORM_KEY + "::context click: [" + m.key + "]"
        );
    }
  }
}

/////////////////////////////////
//
//
async function initForm(vm) {
  await fetchTranslatedText();
  populateSelectionLists(vm);
}

/////////////////////////////////
//
//
function populateSelectionLists(vm) {
  vm.selectLists.dateFilterTokens.push(
    ...[
      { name: vm.$ay.t("DateRangePast6Hours"), id: "*past6hours*" },
      { name: vm.$ay.t("DateRangePast24Hours"), id: "*past24hours*" },
      { name: vm.$ay.t("DateRangePast7Days"), id: "*past7days*" },
      { name: vm.$ay.t("DateRangePast30Days"), id: "*past30days*" },
      {
        name: vm.$ay.t("DateRangeInTheLastSixMonths"),
        id: "*last6months*"
      },
      { name: vm.$ay.t("DateRangePastYear"), id: "*pastyear*" }
    ]
  );
}

//////////////////////////////////////////////////////////
//
// Ensures UI translated text is available
//
async function fetchTranslatedText() {
  await window.$gz.translation.cacheTranslations([
    "DateRangePast6Hours",
    "DateRangePast24Hours",
    "DateRangePast7Days",
    "DateRangePast30Days",
    "DateRangeInTheLastSixMonths",
    "DateRangePastYear",
    "MetricFileStorage",
    "MetricAttachmentsMB",
    "MetricBackupMB",
    "MetricAvailableDiskSpace",
    "MetricAttachmentsCount",
    "Database",
    "MetricDBSize",
    "MetricTopTablesSize",
    "MetricCPUMemory",
    "MetricAllocatedMemory",
    "MetricWorkingSet",
    "MetricPrivateBytes"
  ]);
}
</script>
