<script setup>
import { useI18n } from "vue-i18n";
import { ref, watch, computed, onMounted, nextTick } from "vue";
import { useQuasar, format, date } from "quasar";
import { q, useLight, showUploadFilesDialog, showDocumentDialog } from "#imports";
import { getGrantedRights } from "@hostlink/light";
import { fs } from "@hostlink/light";
const { humanStorageSize } = format;
const light = useLight();
const i18n = useI18n();
const $q = useQuasar();
const emit = defineEmits(["input", "close"]);
const fss = await q({
  app: {
    fs: {
      list: true
    }
  }
}).then((res) => res.app.fs.list);
const folders = ref([]);
const files = ref([]);
const nodes = fss.map((drive) => {
  return {
    icon: "sym_o_storage",
    name: drive.name,
    location: drive.name + "://",
    path: "/",
    lazy: true,
    driveIndex: drive.index,
    type: "drive"
  };
});
const expandedKeys = ref(nodes.map((n) => n.location));
onMounted(async () => {
  await nextTick();
  if (!folderTree.value) return;
  for (const key of expandedKeys.value) {
    folderTree.value.setExpanded(key, true);
  }
  if (nodes.length > 0) {
    selectedLocation.value = nodes[0].location;
  }
});
const onLazyLoad = async ({ node, key, done, fail }) => {
  const folder = await fs.list(node.location);
  const folders2 = folder.children.filter((item) => item.__typename === "Folder").map((item) => {
    item.lazy = true;
    return item;
  });
  done(folders2);
};
const props = defineProps({
  closeable: Boolean,
  height: {
    type: String,
    default: "700px"
  },
  defaultAction: {
    default: "preview",
    type: String
  },
  multiple: {
    default: false,
    type: Boolean
  },
  base: {
    default: "/",
    type: String
  }
});
const loading = ref(false);
const folderTree = ref(null);
const pagination = {
  rowsPerPage: 0,
  "rows-per-page-options": [0]
};
const columns = ref([
  {
    name: "icon",
    label: "",
    field: "type"
  },
  {
    name: "name",
    label: i18n.t("Name"),
    field: "name",
    sortable: true,
    align: "left"
  },
  {
    name: "last_modified",
    label: i18n.t("Last Modified"),
    field: "lastModified",
    sortable: true,
    format: (value) => {
      if (value) {
        return date.formatDate(value * 1e3, "YYYY-MM-DD HH:mm:ss");
      }
      return "";
    },
    align: "left"
  },
  {
    name: "size_display",
    label: i18n.t("Size"),
    field: "size",
    align: "right",
    sortable: true,
    format: (val) => {
      if (val == null) {
        return "";
      }
      return humanStorageSize(val);
    }
  },
  { name: "action" }
]);
const localSearch = ref(null);
const rightDrawerOpen = ref(false);
const leftDrawerOpen = ref(false);
function toggleLeftDrawer() {
  leftDrawerOpen.value = !leftDrawerOpen.value;
}
const loadItems = async () => {
  let path = selectedLocation.value;
  files.value = [];
  folders.value = [];
  if (label.value || localSearch.value) {
    loading.value = true;
    const items2 = await fs.find(localSearch.value, label.value);
    loading.value = false;
    files.value = items2.filter((item) => item.__typename === "File");
    folders.value = items2.filter((item) => item.__typename === "Folder");
    return;
  }
  if (!path) {
    return;
  }
  loading.value = true;
  const folder = await fs.list(path);
  loading.value = false;
  files.value = folder.children.filter((item) => item.__typename === "File");
  if (!label.value && !localSearch.value) {
    folders.value = folder.children.filter((item) => item.__typename === "Folder").map((item) => {
      item.lazy = true;
      return item;
    });
    reloadTreeFolder(selectedLocation.value, folders.value);
  }
};
const label = ref(null);
watch(label, () => {
  loadItems();
});
const selected = ref([]);
const onClickRow = (evt, row, index) => {
  if (row.__typename == "Folder") {
    preview.value = null;
    return;
  }
  preview.value = row;
};
const grid = ref(false);
const onDblclickRow = (evt, row, index) => {
  if (row.__typename == "Folder") {
    selectedLocation.value = row.location;
    return;
  }
  if (row.__typename == "File") {
    emit("input", row.path, row);
  }
};
const findFolder = (path, folders2) => {
  folders2.value.forEach((item) => {
    if (item.path == path) {
      return item;
    }
    let found = findFolder(path, item.children);
    if (found) {
      return found;
    }
  });
};
const reloadTreeFolder = (path, newFolders) => {
  let node = folderTree.value.getNodeByKey(path);
  if (node) {
    node.lazy = false;
    node.children = newFolders;
    folderTree.value.setExpanded(path, true);
  }
};
const onDeleteSelected = () => {
  $q.dialog({
    title: "Delete",
    message: "Are you sure you want to delete this files or folders?",
    cancel: true
  }).onOk(async () => {
    loading.value = true;
    for (let row of selected.value) {
      if (row.__typename == "Folder") {
        await fs.deleteFolder(row.location);
      } else {
        await fs.deleteFile(row.location);
      }
    }
    loading.value = false;
    selected.value = [];
    preview.value = null;
    await loadItems();
  });
};
const onNewFolder = () => {
  $q.dialog({
    title: "New Folder",
    prompt: {
      model: "",
      label: "Name",
      isValid: (val) => {
        return val.length > 0;
      },
      hint: "Create a new folder in " + selectedLocation.value
    },
    cancel: true
  }).onOk(async (name) => {
    loading.value = true;
    await fs.createFolder(selectedLocation.value + "/" + name);
    await loadItems();
    loading.value = false;
  });
};
const onDeleteRow = (node) => {
  if (node.__typename == "File") {
    $q.dialog({
      title: "Delete",
      message: "Are you sure you want to delete this file?",
      cancel: true
    }).onOk(async () => {
      loading.value = true;
      await fs.deleteFile(node.location);
      await loadItems();
      loading.value = false;
    });
  } else if (node.__typename == "Folder") {
    $q.dialog({
      title: "Delete",
      message: "Are you sure you want to delete this folder?",
      cancel: true
    }).onOk(async () => {
      loading.value = true;
      await fs.deleteFolder(node.location);
      await loadItems();
      loading.value = false;
    });
  }
};
const onRenameNode = (node) => {
  $q.dialog({
    title: "Rename " + node.__typename,
    prompt: {
      label: "Name",
      model: node.name
    },
    cancel: true
  }).onOk(async (name) => {
    try {
      if (node.__typename == "File") {
        await fs.renameFile(node.location, name);
      } else {
        await fs.renameFolder(node.location, name);
      }
      await loadItems();
    } catch (e) {
      $q.notify({
        title: "Error",
        message: e.message,
        type: "negative"
      });
    }
  });
};
const openUploadDialog = () => {
  showUploadFilesDialog(selectedLocation.value).onOk((files2) => {
    loadItems().then(() => {
      selectUploadedFiles(files2);
    });
  });
};
const selectUploadedFiles = (uploadedFiles) => {
  if (!uploadedFiles || uploadedFiles.length === 0) return;
  const uploadedNames = new Set(
    uploadedFiles.map((f) => f && f.name ? f.name : null).filter(Boolean)
  );
  if (uploadedNames.size === 0) return;
  const matches = files.value.filter((f) => f && f.name && uploadedNames.has(f.name));
  if (matches.length === 0) return;
  const existingLocs = new Set(selected.value.map((s) => s.location));
  const merged = [...selected.value];
  for (const m of matches) {
    if (!existingLocs.has(m.location)) {
      merged.push(m);
    }
  }
  selected.value = merged;
};
const preview = ref(null);
const moveToFolder = async (folder) => {
  try {
    for (let node of selected.value) {
      await fs.move(node.location, folder);
    }
  } catch (e) {
    $q.dialog({
      title: "Error",
      message: e.message
    });
  }
  await loadItems();
};
const submitSearch = (e) => {
  localSearch.value = search.value;
  loadItems();
};
const onDownloadNode = async (node) => {
  const base64Content = await fs.readFile(node.location, "base64");
  const downloadLink = document.createElement("a");
  downloadLink.href = `data:${node.mimeType};base64,${base64Content}`;
  downloadLink.download = node.name;
  downloadLink.click();
};
const search = ref(null);
const permission = await getGrantedRights([
  "fs.folder.create",
  "fs.folder.delete",
  "fs.folder.rename",
  "fs.file.delete",
  "fs.file.rename",
  "fs.file.upload"
]);
const canDeleteRow = (row) => {
  if (row.__typename == "Folder" && permission.includes("fs.folder.delete")) {
    return true;
  }
  if (row.__typename == "File" && permission.includes("fs.file.delete")) {
    return true;
  }
  return false;
};
const canRenameRow = (row) => {
  if (row.__typename == "Folder" && permission.includes("fs.folder.rename")) {
    return true;
  }
  if (row.__typename == "File" && permission.includes("fs.file.rename")) {
    return true;
  }
  return false;
};
const showPreviewImgDialog = ref(false);
const previewImg = ref(null);
const isDark = computed(() => light.isDarkMode());
const getFilePublicUrl = async (location) => {
  const file = await q({
    app: {
      fs: {
        node: {
          __args: {
            location
          },
          __typename: true,
          __on: {
            __typeName: "File",
            publicUrl: true
          }
        }
      }
    }
  }).then((res) => res.app.fs.node);
  return file.publicUrl;
};
const onPreview = async (node) => {
  showDocumentDialog({
    url: await getFilePublicUrl(node.location),
    mimeType: node.mimeType,
    title: node.name
  });
};
const onClickInfo = async (row) => {
  rightDrawerOpen.value = true;
};
const items = computed(() => {
  return [...folders.value, ...files.value];
});
const selectedLocation = ref(null);
watch(selectedLocation, async () => {
  selected.value = [];
  await loadItems();
});
const canPreview = (file) => {
  if (!file.mimeType) {
    return false;
  }
  return file.mimeType.startsWith("image/") || file.mimeType === "text/plain" || file.mimeType === "application/pdf" || file.mimeType.startsWith("video/") || file.mimeType.startsWith("audio/");
};
const onCheckTotalSize = async (folder) => {
  const d = $q.dialog({
    title: "Total Size",
    progress: true
  });
  const node = await q({
    app: {
      fs: {
        node: {
          __args: {
            location: folder.location
          },
          __typename: true,
          name: true,
          __on: {
            __typeName: "Folder",
            totalSize: true
          }
        }
      }
    }
  }).then((res) => res.app.fs.node);
  d.update({
    message: "Total size of folder '" + node.name + "' is " + humanStorageSize(node.totalSize),
    progress: false
  });
};
const onDuplicateFile = async (file) => {
  try {
    const newPath = await fs.duplicateFile(file.location);
    $q.notify({
      type: "positive",
      message: "File duplicated to " + newPath
    });
  } catch (e) {
    $q.dialog({
      title: "Error",
      message: e.message
    });
    return;
  }
  await loadItems();
};
const onDrop = (event) => {
  event.preventDefault();
  event.stopPropagation();
  if (selectedLocation.value == null) {
    $q.notify({
      type: "warning",
      message: "Please select a folder to upload files."
    });
    return;
  }
  const files2 = event.dataTransfer.files;
  console.log("Dropped files:", files2);
  if (files2.length > 0) {
    const fileList = Array.from(files2);
    showUploadFilesDialog(selectedLocation.value, fileList).onOk((uploadedFiles) => {
      loadItems().then(() => {
        selectUploadedFiles(uploadedFiles);
      });
    });
  }
  dragzone.value.style.border = "none";
};
const dragzone = ref(null);
const onDragover = (event) => {
  event.preventDefault();
  event.stopPropagation();
  if (selectedLocation.value == null) {
    return;
  }
  dragzone.value.style.border = "2px dashed #1976d2";
};
const onDragLeave = (event) => {
  event.preventDefault();
  event.stopPropagation();
  if (selectedLocation.value == null) {
    return;
  }
  dragzone.value.style.border = "none";
};
const getFileIcon = (file) => {
  if (!file.mimeType) {
    return "sym_o_description";
  }
  if (file.mimeType.startsWith("image/")) {
    return "sym_o_image";
  } else if (file.mimeType === "application/pdf") {
    return "sym_o_picture_as_pdf";
  } else if (file.mimeType.startsWith("video/")) {
    return "sym_o_videocam";
  } else if (file.mimeType.startsWith("audio/")) {
    return "sym_o_audiotrack";
  } else if (file.mimeType === "application/zip" || file.mimeType === "application/x-rar-compressed") {
    return "sym_o_archive";
  } else {
    return "sym_o_description";
  }
};
</script>

<template>
  <q-layout view="hHh lpR fFf" :class="isDark ? '' : 'bg-white'" container :style="{ 'min-height': height }">
    <q-header bordered :class="isDark ? '' : 'bg-white text-grey-8'" height-hint="64">
      <q-toolbar>
        <q-btn flat round @click="toggleLeftDrawer" aria-label="Menu" icon="sym_o_menu" class="q-mr-sm" />

        <q-toolbar-title v-if="$q.screen.gt.xs" shrink class="row items-center no-wrap">
          <span class="q-ml-sm">{{ $t('File Manager') }}</span>
        </q-toolbar-title>

        <div>
          <q-input outlined :placeholder="$t('Search for file name')" dense @keyup.enter.native="submitSearch"
            v-model="search">
            <template v-slot:append>
              <q-btn flat dense round icon="sym_o_search"></q-btn>
            </template>
          </q-input>
        </div>

        <q-space></q-space>
        <q-btn v-if="closeable" icon="close" flat round @click="$emit('close')"></q-btn>
      </q-toolbar>
    </q-header>

    <q-drawer v-model="leftDrawerOpen" show-if-above bordered :width="257">
      <q-scroll-area class="fit">
        <q-list padding class="text-grey-8">
          <q-item>
            <q-item-section>
              <l-btn icon="add" label="New" :disable="!selectedLocation">
                <q-menu>
                  <q-list>
                    <q-item clickable v-close-popup @click="onNewFolder" v-if="permission.includes('fs.folder.create')">
                      <q-item-section avatar>
                        <q-icon name="sym_o_create_new_folder"></q-icon>
                      </q-item-section>
                      <q-item-section>{{ $t('Folder') }}</q-item-section>
                    </q-item>
                    <q-separator />
                    <q-item clickable v-close-popup @click="openUploadDialog"
                      v-if="permission.includes('fs.file.upload')">
                      <q-item-section avatar>
                        <q-icon name="sym_o_upload_file"></q-icon>
                      </q-item-section>
                      <q-item-section>{{ $t('Upload file') }}</q-item-section>
                    </q-item>
                  </q-list>
                </q-menu>
              </l-btn>
            </q-item-section>
          </q-item>

          <q-tree ref="folderTree" :nodes="nodes" node-key="location" label-key="name" @lazy-load="onLazyLoad"
            v-model:selected="selectedLocation" v-model:expanded="expandedKeys" no-selection-unset>
          </q-tree>

          <q-separator inset class="q-my-sm" />

          <l-file-manager-labels v-model="label" />
        </q-list>
      </q-scroll-area>
    </q-drawer>

    <q-drawer v-model="rightDrawerOpen" side="right" show-if-above bordered>
      <l-file-manager-preview :location="preview.location" v-if="preview" :key="preview.location" />
    </q-drawer>

    <q-page-container :style="{ height }">
      <div @drop="onDrop" @dragover="onDragover" ref="dragzone" @dragleave="onDragLeave" style="height: 100%; display: flex; flex-direction: column; overflow: hidden;">

        <q-dialog v-model="showPreviewImgDialog" full-width full-height auto-close>
          <q-card>
            <q-card-section>
              <q-img :src="previewImg"></q-img>
            </q-card-section>
          </q-card>
        </q-dialog>

        <q-toolbar>
          <l-file-manager-breadcrumbs v-model="selectedLocation" />
          <q-space></q-space>
          <q-btn flat round icon="sym_o_drive_file_move" v-if="selected.length > 0 && selectedLocation">
            <l-file-manager-move @selected="moveToFolder($event)"
              :current_location="selectedLocation"
              :allow_cross_fs="selected.every(item => item.__typename == 'File')" />
            <q-tooltip>
              {{ $t('Move to') }}
            </q-tooltip>
          </q-btn>

          <q-btn flat round icon="sym_o_delete" @click="onDeleteSelected" v-if="selected.length > 0">
            <q-tooltip>
              {{ $t('Delete') }}
            </q-tooltip>
          </q-btn>
          <q-btn flat round :icon="grid ? 'sym_o_view_list' : 'sym_o_grid_view'" @click="grid = !grid">
            <q-tooltip>
              {{ grid ? $t('List view') : $t('Grid view') }}
            </q-tooltip>
          </q-btn>
        </q-toolbar>

        <div class="file-list-scroll" style="flex: 1 1 auto; overflow-y: auto; min-height: 0;">
        <template v-if="grid">
          <q-table :title="$t('Folders')" flat grid :columns="columns" :rows="folders" hide-pagination
            :pagination="{ rowsPerPage: 0 }" row-key="location">
            <template v-slot:item="props">
              <div class="q-pa-xs col-xs-12 col-sm-6 col-md-4" @click="onDblclickRow(null, props.row, null)">
                <q-card flat bordered>
                  <q-item>
                    <q-item-section avatar>
                      <q-icon name="sym_o_folder" size="sm"></q-icon>
                    </q-item-section>
                    <q-item-section>
                      {{ props.row.name }}
                    </q-item-section>
                    <q-item-section avatar>
                      <q-checkbox v-model="selected" :val="props.row" />
                    </q-item-section>
                  </q-item>
                </q-card>
              </div>
            </template>
          </q-table>

          <q-table :title="$t('Files')" flat grid :columns="columns" :rows="files" hide-pagination
            :pagination="{ rowsPerPage: 0 }" row-key="location">

            <template v-slot:item="props">
              <div class="q-pa-xs col-xs-12 col-sm-6 col-md-4" @click="onClickRow(null, props.row, null)">
                <q-card flat bordered>
                  <q-item>
                    <q-item-section avatar>
                      <q-icon :name="getFileIcon(props.row)" size="sm"></q-icon>
                    </q-item-section>
                    <q-item-section>
                      <q-item-label lines="1">
                        {{ props.row.name }}
                      </q-item-label>
                    </q-item-section>
                    <q-item-section side>
                      <q-checkbox v-model="selected" :val="props.row" />
                    </q-item-section>
                  </q-item>

                  <l-document-viewer :url="props.row.publicUrl"
                  height="100px"
                  
                    :mime-type="props.row.mimeType" :title="props.row.name" v-if="props.row.mimeType.startsWith('image/')"  />

                </q-card>
              </div>
            </template>
          </q-table>
        </template>
        <template v-else>

          <q-table flat :columns="columns" :rows="items" @row-dblclick="onDblclickRow" @row-click="onClickRow"
            :pagination="pagination" row-key="location" selection="multiple" v-model:selected="selected" dense
            :loading="loading" :loading-label="$t('Loading...')" :no-data-label="$t('No data available')"
            separator="horizontal" :rows-per-page-options="[0]" color="primary" square>
            <template #body-cell-icon="props">
              <q-td auto-width>
                <q-icon name="sym_o_folder" v-if="props.row.__typename == 'Folder'" size="sm" />
                <q-icon :name="getFileIcon(props.row)" v-else size="sm" />
              </q-td>
            </template>

            <template #body-cell-action="props">
              <q-td auto-width>
                <q-btn flat icon="sym_o_more_vert" round dense>
                  <q-menu>
                    <q-list>

                      <q-item clickable v-close-popup="true" @click="onCheckTotalSize(props.row)"
                        v-if="props.row.__typename == 'Folder'">
                        <q-item-section avatar>
                          <q-icon name="sym_o_info"></q-icon>
                        </q-item-section>
                        <q-item-section>{{ $t('Total size') }}</q-item-section>
                      </q-item>

                      <q-item clickable v-close-popup @click="onDeleteRow(props.row)" v-if="canDeleteRow(props.row)">
                        <q-item-section avatar>
                          <q-icon name="sym_o_delete"></q-icon>
                        </q-item-section>
                        <q-item-section>{{ $t('Delete') }}</q-item-section>
                      </q-item>

                      <q-item v-if="props.row.__typename == 'File'" clickable v-close-popup
                        @click="onDownloadNode(props.row)">
                        <q-item-section avatar>
                          <q-icon name="sym_o_download"></q-icon>
                        </q-item-section>
                        <q-item-section>{{ $t('Download') }}</q-item-section>
                      </q-item>

                      <q-item clickable v-close-popup @click="onRenameNode(props.row)" v-if="canRenameRow(props.row)">
                        <q-item-section avatar>
                          <q-icon name="sym_o_edit"></q-icon>
                        </q-item-section>
                        <q-item-section>{{ $t('Rename') }}</q-item-section>
                      </q-item>

                      <q-item clickable v-close-popup @click="onDuplicateFile(props.row)"
                        v-if="props.row.__typename == 'File'">
                        <q-item-section avatar>
                          <q-icon name="sym_o_content_copy"></q-icon>
                        </q-item-section>
                        <q-item-section>{{ $t('Duplicate') }}</q-item-section>
                      </q-item>

                      <q-item clickable v-close-popup @click="onPreview(props.row)" v-if="canPreview(props.row)">
                        <q-item-section avatar>
                          <q-icon name="sym_o_preview"></q-icon>
                        </q-item-section>
                        <q-item-section>{{ $t('Preview') }}</q-item-section>
                      </q-item>

                      <q-item clickable v-close-popup @click="onClickInfo(props.row)" class="lt-lg">
                        <q-item-section avatar>
                          <q-icon name="sym_o_info"></q-icon>
                        </q-item-section>
                        <q-item-section>{{ $t('Info') }}</q-item-section>
                      </q-item>

                    </q-list>
                  </q-menu>
                </q-btn>
              </q-td>
            </template>
          </q-table>
        </template>
        </div>
      </div>
    </q-page-container>
  </q-layout>
</template>
