<template>
   <Teleport to="#window-content">
      <div class="modal active">
         <ModalProcessesListContext
            v-if="isContext"
            :context-event="contextEvent"
            :selected-row="selectedRow"
            :selected-cell="selectedCell"
            @copy-cell="copyCell"
            @copy-row="copyRow"
            @kill-process="killProcess"
            @close-context="closeContext"
         />
         <a class="modal-overlay" @click.stop="closeModal" />
         <div ref="trapRef" class="modal-container p-0 pb-4">
            <div class="modal-header pl-2">
               <div class="modal-title h6">
                  <div class="d-flex">
                     <BaseIcon
                        icon-name="mdiMemory"
                        class="mr-1"
                        :size="24"
                     />
                     <span class="cut-text">{{ t('database.processesList') }}: {{ connectionName }}</span>
                  </div>
               </div>
               <a class="btn btn-clear c-hand" @click.stop="closeModal" />
            </div>
            <div class="processes-toolbar py-2 px-4">
               <div class="workspace-query-buttons">
                  <div class="dropdown pr-1">
                     <div class="btn-group">
                        <button
                           class="btn btn-dark btn-sm mr-0 pr-1 d-flex"
                           :class="{'loading':isQuering}"
                           :title="`${t('general.refresh')}`"
                           @click="getProcessesList"
                        >
                           <BaseIcon
                              v-if="!+autorefreshTimer"
                              icon-name="mdiRefresh"
                              :size="24"
                           />
                           <BaseIcon
                              v-else
                              icon-name="mdiHistory"
                              flip="horizontal"
                              class="mr-1"
                              :size="24"
                           />
                        </button>
                        <div class="btn btn-dark btn-sm dropdown-toggle pl-0 pr-0" tabindex="0">
                           <BaseIcon icon-name="mdiMenuDown" :size="24" />
                        </div>
                        <div class="menu px-3">
                           <span>{{ t('general.autoRefresh') }}: <b>{{ +autorefreshTimer ? `${autorefreshTimer}s` : 'OFF' }}</b></span>
                           <input
                              v-model="autorefreshTimer"
                              class="slider no-border"
                              type="range"
                              min="0"
                              max="15"
                              step="0.5"
                              @change="setRefreshInterval"
                           >
                        </div>
                     </div>
                  </div>
                  <div class="dropdown table-dropdown">
                     <button
                        :disabled="isQuering"
                        class="btn btn-dark btn-sm dropdown-toggle d-flex mr-0 pr-0"
                        tabindex="0"
                     >
                        <BaseIcon icon-name="mdiFileExport" :size="24" />
                        <span>{{ t('database.export') }}</span>
                        <BaseIcon icon-name="mdiMenuDown" :size="24" />
                     </button>
                     <ul class="menu text-left">
                        <li class="menu-item">
                           <a class="c-hand" @click="downloadTable('json')">JSON</a>
                        </li>
                        <li class="menu-item">
                           <a class="c-hand" @click="downloadTable('csv')">CSV</a>
                        </li>
                     </ul>
                  </div>
               </div>
               <div class="workspace-query-info">
                  <div v-if="sortedResults.length">
                     {{ t('database.processes') }}: <b>{{ sortedResults.length.toLocaleString() }}</b>
                  </div>
               </div>
            </div>
            <div class="modal-body py-0 workspace-query-results">
               <div
                  ref="tableWrapper"
                  class="vscroll"
                  :style="{'height': resultsSize+'px'}"
               >
                  <div ref="table" class="table table-hover">
                     <div class="thead">
                        <div class="tr">
                           <div
                              v-for="(field, index) in fields"
                              :key="index"
                              class="th c-hand"
                           >
                              <div ref="columnResize" class="column-resizable">
                                 <div class="table-column-title" @click="sort(field)">
                                    <span>{{ field.toUpperCase() }}</span>

                                    <BaseIcon
                                       v-if="currentSort === field"
                                       :icon-name="currentSortDir === 'asc' ? 'mdiSortAscending':'mdiSortDescending'"
                                       :size="18"
                                       class="ml-1"
                                    />
                                 </div>
                              </div>
                           </div>
                        </div>
                     </div>
                     <BaseVirtualScroll
                        ref="resultTable"
                        :items="sortedResults"
                        :item-height="22"
                        class="tbody"
                        :visible-height="resultsSize"
                        :scroll-element="scrollElement"
                     >
                        <template #default="{ items }">
                           <ModalProcessesListRow
                              v-for="row in items"
                              :key="row.id"
                              class="process-row"
                              :row="row"
                              @select-row="selectRow(row.id)"
                              @contextmenu="contextMenu"
                              @stop-refresh="stopRefresh"
                           />
                        </template>
                     </BaseVirtualScroll>
                  </div>
               </div>
            </div>
         </div>
      </div>
   </Teleport>
</template>

<script setup lang="ts">
import { ConnectionParams } from 'common/interfaces/antares';
import { ipcRenderer } from 'electron';
import { Component, computed, onBeforeUnmount, onMounted, onUpdated, Prop, Ref, ref } from 'vue';
import { useI18n } from 'vue-i18n';

import BaseIcon from '@/components/BaseIcon.vue';
import BaseVirtualScroll from '@/components/BaseVirtualScroll.vue';
import ModalProcessesListContext from '@/components/ModalProcessesListContext.vue';
import ModalProcessesListRow from '@/components/ModalProcessesListRow.vue';
import { useFocusTrap } from '@/composables/useFocusTrap';
import Schema from '@/ipc-api/Schema';
import { copyText } from '@/libs/copyText';
import { useConnectionsStore } from '@/stores/connections';
import { useNotificationsStore } from '@/stores/notifications';

import { exportRows } from '../libs/exportRows';

const { t } = useI18n();

const { addNotification } = useNotificationsStore();
const { getConnectionName } = useConnectionsStore();

const { trapRef } = useFocusTrap();

const props = defineProps({
   connection: Object as Prop<ConnectionParams>
});

const emit = defineEmits(['close']);

const tableWrapper: Ref<HTMLDivElement> = ref(null);
const table: Ref<HTMLDivElement> = ref(null);
const resultTable: Ref<Component & {updateWindow: () => void}> = ref(null);
const resultsSize = ref(1000);
const isQuering = ref(false);
const isContext = ref(false);
const autorefreshTimer = ref(0);
const refreshInterval: Ref<NodeJS.Timeout> = ref(null);
const contextEvent = ref(null);
const selectedCell = ref(null);
const selectedRow: Ref<number> = ref(null);
const results = ref([]);
const fields = ref([]);
const currentSort = ref('');
const currentSortDir = ref('asc');
const scrollElement = ref(null);

const connectionName = computed(() => getConnectionName(props.connection.uid));

const sortedResults = computed(() => {
   if (currentSort.value) {
      return [...results.value].sort((a, b) => {
         let modifier = 1;
         const valA = typeof a[currentSort.value] === 'string' ? a[currentSort.value].toLowerCase() : a[currentSort.value];
         const valB = typeof b[currentSort.value] === 'string' ? b[currentSort.value].toLowerCase() : b[currentSort.value];
         if (currentSortDir.value === 'desc') modifier = -1;
         if (valA < valB) return -1 * modifier;
         if (valA > valB) return 1 * modifier;
         return 0;
      });
   }
   else
      return results.value;
});

const getProcessesList = async () => {
   isQuering.value = true;

   try { // Table data
      const { status, response } = await Schema.getProcesses(props.connection.uid);

      if (status === 'success') {
         results.value = response;
         fields.value = response.length ? Object.keys(response[0]) : [];
      }
      else
         addNotification({ status: 'error', message: response });
   }
   catch (err) {
      addNotification({ status: 'error', message: err.stack });
   }

   isQuering.value = false;
};

const setRefreshInterval = () => {
   clearRefresh();

   if (+autorefreshTimer.value) {
      refreshInterval.value = setInterval(() => {
         if (!isQuering.value)
            getProcessesList();
      }, autorefreshTimer.value * 1000);
   }
};

const clearRefresh = () => {
   if (refreshInterval.value)
      clearInterval(refreshInterval.value);
};

const resizeResults = () => {
   if (resultTable.value) {
      const el = tableWrapper.value.parentElement;

      if (el) {
         const size = el.offsetHeight;
         resultsSize.value = size;
      }
      resultTable.value.updateWindow();
   }
};

const refreshScroller = () => resizeResults();

const sort = (field: string) => {
   if (field === currentSort.value) {
      if (currentSortDir.value === 'asc')
         currentSortDir.value = 'desc';
      else
         resetSort();
   }
   else {
      currentSortDir.value = 'asc';
      currentSort.value = field;
   }
};

const resetSort = () => {
   currentSort.value = '';
   currentSortDir.value = 'asc';
};

const stopRefresh = () => {
   autorefreshTimer.value = 0;
   clearRefresh();
};

const selectRow = (row: number) => {
   selectedRow.value = Number(row);
};

const contextMenu = (event: MouseEvent, cell: { id: number; field: string }) => {
   if ((event.target as HTMLElement).localName === 'input') return;
   stopRefresh();

   selectedCell.value = cell;
   selectedRow.value = Number(cell.id);
   contextEvent.value = event;
   isContext.value = true;
};

const killProcess = async () => {
   try { // Table data
      const { status, response } = await Schema.killProcess({ uid: props.connection.uid, pid: selectedRow.value });

      if (status === 'success')
         getProcessesList();
      else
         addNotification({ status: 'error', message: response });
   }
   catch (err) {
      addNotification({ status: 'error', message: err.stack });
   }
};

const closeContext = () => {
   isContext.value = false;
};

const copyCell = () => {
   const row = results.value.find(row => Number(row.id) === selectedRow.value);
   const valueToCopy = row[selectedCell.value.field];
   copyText(valueToCopy);
};

const copyRow = () => {
   const row = results.value.find(row => Number(row.id) === selectedRow.value);
   const rowToCopy = JSON.parse(JSON.stringify(row));
   copyText(JSON.stringify(rowToCopy));
};

const closeModal = () => emit('close');

const downloadTable = (format: 'csv' | 'json') => {
   if (!sortedResults.value) return;
   exportRows({
      type: format,
      content: sortedResults.value,
      table: 'processes'
   });
};

const onKey = (e:KeyboardEvent) => {
   e.stopPropagation();
   if (e.key === 'Escape')
      closeModal();
};

ipcRenderer.on('run-or-reload', getProcessesList);

window.addEventListener('keydown', onKey, { capture: true });

onMounted(() => {
   getProcessesList();
   window.addEventListener('resize', resizeResults);
});

onUpdated(() => {
   if (table.value)
      refreshScroller();
   if (tableWrapper.value)
      scrollElement.value = tableWrapper.value;
});

onBeforeUnmount(() => {
   window.removeEventListener('keydown', onKey, { capture: true });
   window.removeEventListener('resize', resizeResults);
   clearInterval(refreshInterval.value);

   ipcRenderer.removeListener('run-or-reload', getProcessesList);
});

defineExpose({ refreshScroller });
</script>

<style lang="scss" scoped>
.vscroll {
  height: 1000px;
  overflow: auto;
  overflow-anchor: none;
}

.column-resizable {
  &:hover,
  &:active {
    resize: horizontal;
    overflow: hidden;
  }
}

.table-column-title {
  display: flex;
  align-items: center;
}

.sort-icon {
  font-size: 0.7rem;
  line-height: 1;
  margin-left: 0.2rem;
}

.result-tabs {
  background: transparent !important;
  margin: 0;
}

.modal {
  align-items: flex-start;

  .modal-container {
    max-width: 75vw;
    margin-top: 10vh;

    .modal-body {
      height: 80vh;
    }
  }
}

.processes-toolbar {
  display: flex;
  justify-content: space-between;
}
</style>
