<template>
    <div>
        <div class="flex sm:flex-row flex-col justify-start gap-y-2 items-center gap-x-4" ref="toolRef">
            <div class="flex-shrink-0 flex sm:w-min w-full items-center justify-start">
                <el-tooltip :content="$t('file.back')" placement="top">
                    <el-button icon="Back" @click="back" circle />
                </el-tooltip>
                <el-tooltip :content="$t('file.right')" placement="top">
                    <el-button icon="Right" @click="right" circle />
                </el-tooltip>
                <el-tooltip :content="$t('file.top')" placement="top">
                    <el-button icon="Top" @click="top" circle :disabled="paths.length == 0" />
                </el-tooltip>
                <el-tooltip :content="$t('commons.button.refresh')" placement="top">
                    <el-button icon="Refresh" circle @click="search" />
                </el-tooltip>
                <el-tooltip :content="req.showHidden ? $t('file.noShowHide') : $t('file.showHide')" placement="top">
                    <el-button
                        class="btn"
                        circle
                        :type="req.showHidden ? '' : 'primary'"
                        :icon="req.showHidden ? View : Hide"
                        @click="viewHideFile"
                    />
                </el-tooltip>
            </div>
            <div class="flex-1 sm:w-min w-full hidden sm:block" ref="pathRef">
                <div
                    v-show="!searchableStatus"
                    @click="searchableStatus = true"
                    class="address-bar shadow-md rounded-md px-4 py-2 flex items-center flex-grow"
                >
                    <div ref="breadCrumbRef" class="flex items-center address-url">
                        <span class="root mr-2">
                            <el-link @click.stop="jump('/')">
                                <el-icon :size="20"><HomeFilled /></el-icon>
                            </el-link>
                        </span>
                        <span v-for="(path, index) in paths" :key="path.url" class="inline-flex items-center">
                            <span class="mr-2 arrow">></span>
                            <template v-if="index === 0 && hidePaths.length > 0">
                                <el-dropdown>
                                    <span
                                        class="path-segment cursor-pointer mr-2 pathname focus:outline-none focus-visible:outline-none"
                                    >
                                        ..
                                    </span>
                                    <template #dropdown>
                                        <el-dropdown-menu>
                                            <el-dropdown-item
                                                v-for="hidePath in hidePaths"
                                                :key="hidePath.url"
                                                @click.stop="jump(hidePath.url)"
                                            >
                                                <el-tooltip
                                                    class="box-item"
                                                    effect="dark"
                                                    :content="hidePath.name"
                                                    placement="bottom"
                                                >
                                                    {{
                                                        hidePath.name.length > 25
                                                            ? hidePath.name.substring(0, 22) + '...'
                                                            : hidePath.name
                                                    }}
                                                </el-tooltip>
                                            </el-dropdown-item>
                                        </el-dropdown-menu>
                                    </template>
                                </el-dropdown>
                                <span class="mr-2 arrow">></span>
                                <el-tooltip class="box-item" effect="dark" :content="path.name" placement="bottom">
                                    <el-link
                                        class="path-segment cursor-pointer mr-2 pathname"
                                        @click.stop="jump(path.url)"
                                    >
                                        {{ path.name.length > 25 ? path.name.substring(0, 22) + '...' : path.name }}
                                    </el-link>
                                </el-tooltip>
                            </template>
                            <template v-else>
                                <el-tooltip class="box-item" effect="dark" :content="path.name" placement="bottom">
                                    <el-link
                                        class="path-segment cursor-pointer mr-2 pathname"
                                        @click.stop="jump(path.url)"
                                    >
                                        {{ path.name.length > 25 ? path.name.substring(0, 22) + '...' : path.name }}
                                    </el-link>
                                </el-tooltip>
                            </template>
                        </span>
                    </div>
                </div>
                <el-input
                    ref="searchableInputRef"
                    v-show="searchableStatus"
                    v-model="searchablePath"
                    @blur="searchableInputBlur"
                    class="px-4 py-2 border rounded-md shadow-md"
                    @keyup.enter="
                        jump(searchablePath);
                        searchableStatus = false;
                    "
                />
            </div>
            <div class="flex-1 sm:w-min w-full sm:hidden block">
                <div class="address-bar shadow-md rounded-md px-4 py-2 flex items-center flex-grow">
                    <div class="flex items-center address-url">
                        <span class="root mr-2">
                            <el-link @click.stop="jump('/')">
                                <el-icon :size="20"><HomeFilled /></el-icon>
                            </el-link>
                        </span>
                        <span v-for="(path, index) in paths" :key="path.url" class="inline-flex items-center">
                            <span class="mr-2 arrow">></span>
                            <template v-if="index === 0 && hidePaths.length > 0">
                                <el-dropdown>
                                    <span
                                        class="path-segment cursor-pointer mr-2 pathname focus:outline-none focus-visible:outline-none"
                                    >
                                        ..
                                    </span>
                                    <template #dropdown>
                                        <el-dropdown-menu>
                                            <el-dropdown-item
                                                v-for="hidePath in hidePaths"
                                                :key="hidePath.url"
                                                @click.stop="jump(hidePath.url)"
                                            >
                                                <el-tooltip
                                                    class="box-item"
                                                    effect="dark"
                                                    :content="hidePath.name"
                                                    placement="bottom"
                                                >
                                                    {{
                                                        hidePath.name.length > 25
                                                            ? hidePath.name.substring(0, 22) + '...'
                                                            : hidePath.name
                                                    }}
                                                </el-tooltip>
                                            </el-dropdown-item>
                                        </el-dropdown-menu>
                                    </template>
                                </el-dropdown>
                                <span class="mr-2 arrow">></span>
                                <el-tooltip class="box-item" effect="dark" :content="path.name" placement="bottom">
                                    <el-link
                                        class="path-segment cursor-pointer mr-2 pathname"
                                        @click.stop="jump(path.url)"
                                    >
                                        {{ path.name.length > 25 ? path.name.substring(0, 22) + '...' : path.name }}
                                    </el-link>
                                </el-tooltip>
                            </template>
                        </span>
                    </div>
                </div>
            </div>
        </div>
        <LayoutContent :title="$t('menu.files')" v-loading="loading">
            <template #prompt>
                <el-alert type="info" :closable="false">
                    <template #title>
                        <span class="input-help whitespace-break-spaces">
                            {{ $t('file.fileHelper') }}
                        </span>
                    </template>
                </el-alert>
            </template>
            <template #leftToolBar>
                <div ref="leftWrapper" class="flex items-center gap-2 flex-wrap">
                    <el-dropdown @command="handleCreate" class="mr-2.5">
                        <el-button type="primary">
                            {{ $t('commons.button.create') }}
                            <el-icon><arrow-down /></el-icon>
                        </el-button>
                        <template #dropdown>
                            <el-dropdown-menu>
                                <el-dropdown-item command="dir">
                                    <svg-icon iconName="p-file-folder"></svg-icon>
                                    {{ $t('file.dir') }}
                                </el-dropdown-item>
                                <el-dropdown-item command="file">
                                    <svg-icon iconName="p-file-normal"></svg-icon>
                                    {{ $t('menu.files') }}
                                </el-dropdown-item>
                            </el-dropdown-menu>
                        </template>
                    </el-dropdown>
                    <el-dropdown class="mr-2.5">
                        <el-button>
                            {{ $t('commons.button.upload') }}/{{ $t('commons.button.download') }}
                            <el-icon><arrow-down /></el-icon>
                        </el-button>
                        <template #dropdown>
                            <el-dropdown-menu>
                                <el-dropdown-item @click="openUpload">
                                    <el-icon><ElUpload /></el-icon>
                                    {{ $t('commons.button.upload') }}
                                </el-dropdown-item>
                                <el-dropdown-item @click="openWget">
                                    <el-icon><ElDownload /></el-icon>
                                    {{ $t('file.remoteFile') }}
                                </el-dropdown-item>
                            </el-dropdown-menu>
                        </template>
                    </el-dropdown>
                    <el-button-group class="sm:!inline-block !flex flex-wrap gap-y-2">
                        <el-button class="btn" @click="openRecycleBin">
                            {{ $t('file.recycleBin') }}
                        </el-button>
                        <el-button class="btn" @click="toTerminal">
                            {{ $t('menu.terminal') }}
                        </el-button>
                        <el-popover placement="bottom" :width="200" trigger="hover" @before-enter="getFavorites">
                            <template #reference>
                                <el-button @click="openFavorite">
                                    {{ $t('file.favorite') }}
                                </el-button>
                            </template>
                            <div class="favorite-item">
                                <el-table :data="favorites">
                                    <el-table-column prop="name">
                                        <template #default="{ row }">
                                            <el-tooltip
                                                class="box-item"
                                                effect="dark"
                                                :content="row.path"
                                                placement="top"
                                            >
                                                <span
                                                    class="table-link text-ellipsis"
                                                    @click="toFavorite(row)"
                                                    type="primary"
                                                >
                                                    <svg-icon
                                                        v-if="row.isDir"
                                                        className="table-icon"
                                                        iconName="p-file-folder"
                                                    ></svg-icon>
                                                    <svg-icon
                                                        v-else
                                                        className="table-icon"
                                                        iconName="p-file-normal"
                                                    ></svg-icon>
                                                    {{ row.name }}
                                                </span>
                                            </el-tooltip>
                                        </template>
                                    </el-table-column>
                                </el-table>
                            </div>
                        </el-popover>
                        <el-button class="btn" @click="calculateSize(req.path)" :loading="disableBtn">
                            {{ $t('file.calculate') }}
                        </el-button>
                        <template v-if="hostMount.length == 1">
                            <el-button class="btn" @click.stop="jump(hostMount[0]?.path)">
                                {{ hostMount[0]?.path }} ({{ $t('file.root') }})
                                {{ formatFileSize(hostMount[0]?.free) }}
                            </el-button>
                        </template>
                        <template v-else>
                            <el-dropdown class="mr-2.5">
                                <el-button class="btn">
                                    {{ hostMount[0]?.path }} ({{ $t('file.root') }})
                                    {{ formatFileSize(hostMount[0]?.free) }}
                                </el-button>
                                <template #dropdown>
                                    <el-dropdown-menu>
                                        <template v-for="(mount, index) in hostMount" :key="mount.path">
                                            <el-dropdown-item v-if="index == 0" @click.stop="jump(mount.path)">
                                                {{ mount.path }} ({{ $t('file.root') }})
                                                {{ formatFileSize(mount.free) }}
                                            </el-dropdown-item>
                                            <el-dropdown-item v-if="index != 0" @click.stop="jump(mount.path)">
                                                {{ mount.path }} ({{ $t('home.mount') }})
                                                {{ formatFileSize(mount.free) }}
                                            </el-dropdown-item>
                                        </template>
                                    </el-dropdown-menu>
                                </template>
                            </el-dropdown>
                        </template>
                    </el-button-group>

                    <el-badge :value="processCount" class="btn" v-if="processCount > 0">
                        <el-button class="btn" @click="openProcess">
                            {{ $t('file.wgetTask') }}
                        </el-button>
                    </el-badge>
                </div>
            </template>
            <template #rightToolBar>
                <div ref="btnWrapper" class="flex items-center gap-2 flex-wrap">
                    <div class="flex items-center gap-2 flex-wrap">
                        <template v-if="visibleButtons.length == 0">
                            <el-dropdown v-if="moreButtons.length">
                                <el-button>
                                    {{ $t('tabs.more') }}
                                    <i class="el-icon-arrow-down el-icon--right" />
                                </el-button>
                                <template #dropdown>
                                    <el-dropdown-menu>
                                        <el-dropdown-item
                                            v-for="btn in moreButtons"
                                            :key="btn.label"
                                            @click="btn.action"
                                            :disabled="selects.length === 0"
                                        >
                                            {{ $t(btn.label) }}
                                        </el-dropdown-item>
                                    </el-dropdown-menu>
                                </template>
                            </el-dropdown>
                        </template>
                        <template v-if="visibleButtons.length > 0">
                            <el-button-group class="flex items-center">
                                <template v-for="btn in visibleButtons" :key="btn.label">
                                    <el-button plain @click="btn.action" :disabled="selects.length === 0">
                                        {{ $t(btn.label) }}
                                    </el-button>
                                </template>

                                <el-dropdown v-if="moreButtons.length">
                                    <el-button>
                                        {{ $t('tabs.more') }}
                                        <i class="el-icon-arrow-down el-icon--right" />
                                    </el-button>
                                    <template #dropdown>
                                        <el-dropdown-menu>
                                            <el-dropdown-item
                                                v-for="btn in moreButtons"
                                                :key="btn.label"
                                                @click="btn.action"
                                                :disabled="selects.length === 0"
                                            >
                                                {{ $t(btn.label) }}
                                            </el-dropdown-item>
                                        </el-dropdown-menu>
                                    </template>
                                </el-dropdown>
                            </el-button-group>
                        </template>
                    </div>
                    <el-button-group class="copy-button" v-if="moveOpen">
                        <el-tooltip class="box-item" effect="dark" :content="$t('file.paste')" placement="bottom">
                            <el-button plain @click="openPaste">{{ $t('file.paste') }}({{ fileMove.count }})</el-button>
                        </el-tooltip>
                        <el-tooltip
                            class="box-item"
                            effect="dark"
                            :content="$t('commons.button.cancel')"
                            placement="bottom"
                        >
                            <el-button plain class="close" icon="Close" @click="closeMove"></el-button>
                        </el-tooltip>
                    </el-button-group>
                    <div class="w-80">
                        <el-input
                            v-model="req.search"
                            clearable
                            @clear="search()"
                            @keydown.enter="search()"
                            :placeholder="$t('file.search')"
                        >
                            <template #prepend>
                                <el-checkbox v-model="req.containSub">
                                    {{ $t('file.sub') }}
                                </el-checkbox>
                            </template>
                            <template #append>
                                <el-button icon="Search" @click="search" round />
                            </template>
                        </el-input>
                    </div>
                </div>
            </template>
            <template #main>
                <ComplexTable
                    :pagination-config="paginationConfig"
                    v-model:selects="selects"
                    ref="tableRef"
                    :data="data"
                    @search="search"
                    @sort-change="changeSort"
                    @cell-mouse-enter="showFavorite"
                    @cell-mouse-leave="hideFavorite"
                    :heightDiff="300"
                >
                    <el-table-column type="selection" width="30" />
                    <el-table-column
                        :label="$t('commons.table.name')"
                        min-width="250"
                        fix
                        show-overflow-tooltip
                        :sortable="'custom'"
                        prop="name"
                    >
                        <template #default="{ row }">
                            <div class="file-row">
                                <div>
                                    <svg-icon
                                        v-if="row.isDir"
                                        className="table-icon"
                                        iconName="p-file-folder"
                                    ></svg-icon>
                                    <svg-icon
                                        v-else
                                        className="table-icon"
                                        :iconName="getIconName(row.extension)"
                                    ></svg-icon>
                                </div>
                                <div class="file-name">
                                    <span class="table-link" @click="open(row)" type="primary">{{ row.name }}</span>
                                    <span v-if="row.isSymlink">-> {{ row.linkPath }}</span>
                                </div>
                                <div>
                                    <el-button
                                        v-if="row.favoriteID > 0"
                                        link
                                        type="warning"
                                        size="large"
                                        icon="StarFilled"
                                        @click="remove(row.favoriteID)"
                                    ></el-button>
                                    <div v-else>
                                        <el-button
                                            v-if="hoveredRowPath === row.path"
                                            link
                                            icon="Star"
                                            @click="addToFavorite(row)"
                                        ></el-button>
                                    </div>
                                </div>
                            </div>
                        </template>
                    </el-table-column>
                    <el-table-column :label="$t('file.mode')" prop="mode" min-width="110">
                        <template #default="{ row }">
                            <el-link underline="never" @click="openMode(row)">{{ row.mode }}</el-link>
                        </template>
                    </el-table-column>
                    <el-table-column :label="$t('commons.table.user')" prop="user" show-overflow-tooltip min-width="90">
                        <template #default="{ row }">
                            <el-link underline="never" @click="openChown(row)">
                                {{ row.user ? row.user : '-' }} ({{ row.uid }})
                            </el-link>
                        </template>
                    </el-table-column>
                    <el-table-column :label="$t('file.group')" prop="group" show-overflow-tooltip>
                        <template #default="{ row }">
                            <el-link underline="never" @click="openChown(row)">
                                {{ row.group ? row.group : '-' }} ({{ row.gid }})
                            </el-link>
                        </template>
                    </el-table-column>
                    <el-table-column :label="$t('file.size')" prop="size" min-width="100" :sortable="'custom'">
                        <template #default="{ row }">
                            <el-button
                                type="primary"
                                link
                                small
                                :loading="row.btnLoading"
                                @click="row.isDir ? getDirSize(row.path) : getFileSize(row.path)"
                            >
                                <span v-if="row.isDir">
                                    <span v-if="row.dirSize === undefined">
                                        {{ $t('file.calculate') }}
                                    </span>
                                    <span v-else>{{ formatFileSize(row.dirSize) }}</span>
                                </span>
                                <span v-else>
                                    {{ formatFileSize(row.size) }}
                                </span>
                            </el-button>
                        </template>
                    </el-table-column>
                    <el-table-column
                        :label="$t('file.updateTime')"
                        prop="modTime"
                        width="180"
                        :formatter="dateFormat"
                        show-overflow-tooltip
                        :sortable="'custom'"
                    ></el-table-column>
                    <fu-table-operations
                        :ellipsis="mobile ? 0 : 2"
                        :buttons="buttons"
                        :label="$t('commons.table.operate')"
                        :min-width="mobile ? 'auto' : 200"
                        :fixed="mobile ? false : 'right'"
                        width="270"
                        fix
                    />
                    <template #paginationLeft>
                        <div class="flex justify-start items-center">
                            <el-text small>
                                {{ $t('file.fileDirNum', [dirNum, fileNum]) }}
                            </el-text>
                            <el-text small>
                                {{ $t('file.currentDir') + $t('file.size') + ' ' }}
                            </el-text>
                            <el-button type="primary" link small :loading="calculateBtn">
                                <span v-if="dirTotalSize == -1" @click="getDirTotalSize(req.path)">
                                    {{ $t('file.calculate') }}
                                </span>
                                <span v-else>
                                    {{ formatFileSize(dirTotalSize) }}
                                </span>
                            </el-button>
                        </div>
                    </template>
                </ComplexTable>
            </template>

            <CreateFile ref="createRef" @close="search" />
            <ChangeRole ref="roleRef" @close="search" />
            <Compress ref="compressRef" @close="search" />
            <Decompress ref="deCompressRef" @close="search" />
            <CodeEditor ref="codeEditorRef" @close="search" />
            <FileRename ref="renameRef" @close="search" />
            <Upload ref="uploadRef" @close="search" />
            <Wget ref="wgetRef" @close="closeWget" />
            <Move ref="moveRef" @close="closeMovePage" />
            <Download ref="downloadRef" @close="search" />
            <Process ref="processRef" @close="closeProcess" />
            <Owner ref="chownRef" @close="search"></Owner>
            <Detail ref="detailRef" />
            <DeleteFile ref="deleteRef" @close="search" />
            <RecycleBin ref="recycleBinRef" @close="search" />
            <Favorite ref="favoriteRef" @close="search" />
            <BatchRole ref="batchRoleRef" @close="search" />
            <VscodeOpenDialog ref="dialogVscodeOpenRef" />
            <Preview ref="previewRef" />
            <TerminalDialog ref="dialogTerminalRef" />
        </LayoutContent>
    </div>
</template>

<script setup lang="ts">
import { computed, nextTick, onMounted, reactive, ref } from 'vue';
import {
    addFavorite,
    computeDepthDirSize,
    computeDirSize,
    fileWgetKeys,
    getFileContent,
    getFilesList,
    removeFavorite,
    searchFavorite,
    searchHostMount,
} from '@/api/modules/files';
import { computeSize, copyText, dateFormat, downloadFile, getFileType, getIcon, getRandomStr } from '@/utils/util';
import { File } from '@/api/interface/file';
import { Languages, Mimetypes } from '@/global/mimetype';
import { useRouter } from 'vue-router';
import { MsgWarning } from '@/utils/message';
import { useSearchable } from './hooks/searchable';
import { ResultData } from '@/api/interface';
import { GlobalStore } from '@/store';
import { Download as ElDownload, Upload as ElUpload, View, Hide } from '@element-plus/icons-vue';

import i18n from '@/lang';
import CreateFile from './create/index.vue';
import ChangeRole from './change-role/index.vue';
import Compress from './compress/index.vue';
import Decompress from './decompress/index.vue';
import Upload from './upload/index.vue';
import FileRename from './rename/index.vue';
import CodeEditor from './code-editor/index.vue';
import Wget from './wget/index.vue';
import Move from './move/index.vue';
import Download from './download/index.vue';
import Owner from './chown/index.vue';
import DeleteFile from './delete/index.vue';
import Process from './process/index.vue';
import Detail from './detail/index.vue';
import RecycleBin from './recycle-bin/index.vue';
import Favorite from './favorite/index.vue';
import BatchRole from './batch-role/index.vue';
import Preview from './preview/index.vue';
import VscodeOpenDialog from '@/components/vscode-open/index.vue';
import { debounce } from 'lodash-es';
import TerminalDialog from './terminal/index.vue';
import { Dashboard } from '@/api/interface/dashboard';
import { CompressExtension, MimetypeByExtensionObject } from '@/enums/files';

const globalStore = GlobalStore();

interface FilePaths {
    url: string;
    name: string;
}

const router = useRouter();
const data = ref();
const tableRef = ref();
let selects = ref<any>([]);

// origin data
const initData = () => ({
    path: '/',
    expand: true,
    showHidden: true,
    page: 1,
    pageSize: 100,
    search: '',
    containSub: false,
    sortBy: 'name',
    sortOrder: 'ascending',
});
let req = reactive(initData());
let loading = ref(false);
const paths = ref<FilePaths[]>([]);
const hidePaths = ref<FilePaths[]>([]);
let pathWidth = ref(0);
const history: string[] = [];
let pointer = -1;

const fileCreate = reactive({ path: '/', isDir: false, mode: 0o755 });
const fileCompress = reactive({ files: [''], name: '', dst: '', operate: 'compress' });
const fileDeCompress = reactive({ path: '', name: '', dst: '', mimeType: '' });
const fileEdit = reactive({ content: '', path: '', name: '', language: 'plaintext', extension: '' });
const filePreview = reactive({ path: '', name: '', extension: '', fileType: '', imageFiles: [], currentNode: '' });
const codeReq = reactive({ path: '', expand: false, page: 1, pageSize: 100, isDetail: false });
const fileUpload = reactive({ path: '' });
const fileRename = reactive({ path: '', oldName: '' });
const fileWget = reactive({ path: '' });
const fileMove = reactive({ oldPaths: [''], allNames: [''], type: '', path: '', name: '', count: 0, isDir: false });

const createRef = ref();
const roleRef = ref();
const detailRef = ref();
const compressRef = ref();
const deCompressRef = ref();
const codeEditorRef = ref();
const renameRef = ref();
const uploadRef = ref();
const wgetRef = ref();
const moveRef = ref();
const downloadRef = ref();
const pathRef = ref();
const toolRef = ref();
const breadCrumbRef = ref();
const chownRef = ref();
const moveOpen = ref(false);
const deleteRef = ref();
const recycleBinRef = ref();
const favoriteRef = ref();
const hoveredRowPath = ref(null);
const favorites = ref([]);
const batchRoleRef = ref();
const dialogVscodeOpenRef = ref();
const previewRef = ref();
const processRef = ref();
const hostMount = ref<Dashboard.DiskInfo[]>([]);
let resizeObserver: ResizeObserver;
const dirTotalSize = ref(-1);
const disableBtn = ref(false);
const calculateBtn = ref(false);
const dirNum = ref(0);
const fileNum = ref(0);
const imageFiles = ref([]);

const { searchableStatus, searchablePath, searchableInputRef, searchableInputBlur } = useSearchable(paths);

const paginationConfig = reactive({
    cacheSizeKey: 'file-page-size',
    currentPage: 1,
    pageSize: 100,
    total: 0,
});

const mobile = computed(() => {
    return globalStore.isMobile();
});

const search = async () => {
    dirTotalSize.value = -1;
    getWgetProcess();
    loading.value = true;
    if (req.search != '') {
        req.sortBy = 'name';
        req.sortOrder = 'ascending';
        tableRef.value.clearSort();
    }

    req.page = paginationConfig.currentPage;
    req.pageSize = paginationConfig.pageSize;
    await getFilesList(req)
        .then((res) => {
            handleSearchResult(res);
        })
        .finally(() => {
            loading.value = false;
        });
};

const searchFile = async () => {
    loading.value = true;
    dirTotalSize.value = -1;
    try {
        return await getFilesList(req);
    } finally {
        loading.value = false;
    }
};

const handleSearchResult = (res: ResultData<File.File>) => {
    data.value = res.data.items || [];
    paginationConfig.total = res.data.itemTotal;
    dirNum.value = data.value.filter((item) => item.isDir).length;
    fileNum.value = data.value.filter((item) => !item.isDir).length;
    req.path = res.data.path;
};

const viewHideFile = async () => {
    req.showHidden = !req.showHidden;
    localStorage.setItem('show-hidden', req.showHidden ? 'true' : 'false');
    let searchResult = await searchFile();
    handleSearchResult(searchResult);
};

const open = async (row: File.File) => {
    calculateBtn.value = false;
    disableBtn.value = false;
    if (row.isDir) {
        if (row.name.indexOf('.1panel_clash') > -1) {
            MsgWarning(i18n.global.t('file.clashOpenAlert'));
            return;
        }
        const name = row.name;
        if (req.path.endsWith('/')) {
            req.path = req.path + name;
        } else {
            req.path = req.path + '/' + name;
        }
        paths.value.push({
            url: req.path,
            name: name,
        });
        jump(req.path);
    } else {
        openView(row);
    }
};

const copyDir = (row: File.File) => {
    if (row?.path) {
        copyText(row?.path);
    }
};

const btnWrapper = ref<HTMLElement | null>(null);
const leftWrapper = ref<HTMLElement | null>(null);
const toolButtons = ref([
    {
        label: 'commons.button.copy',
        action: () => openMove('copy'),
    },
    {
        label: 'file.move',
        action: () => openMove('cut'),
    },
    {
        label: 'file.compress',
        action: () => openCompress(selects.value),
    },
    {
        label: 'file.role',
        action: () => openBatchRole(selects.value),
    },
    {
        label: 'commons.button.delete',
        action: () => batchDelFiles(),
    },
]);

const visibleButtons = ref([...toolButtons.value]);
const moreButtons = ref([]);

const updateButtons = async () => {
    await nextTick();
    if (!btnWrapper.value) return;
    const pathWidth = toolRef.value.offsetWidth;
    const leftWidth = leftWrapper.value.offsetWidth;
    let num = Math.floor((pathWidth - leftWidth - 450) / 100);
    if (num < 0) {
        visibleButtons.value = toolButtons.value;
        moreButtons.value = [];
    } else {
        visibleButtons.value = toolButtons.value.slice(0, num);
        moreButtons.value = toolButtons.value.slice(num);
    }
};

const handlePath = () => {
    nextTick(function () {
        let breadCrumbWidth = breadCrumbRef.value.offsetWidth;
        let pathWidth = toolRef.value.offsetWidth;
        if (pathWidth - breadCrumbWidth < 50 && paths.value.length > 1) {
            const removed = paths.value.shift();
            if (removed) hidePaths.value.push(removed);
            handlePath();
        }
    });
};

const resizeHandler = debounce(() => {
    resetPaths();
    handlePath();
}, 100);

const btnResizeHandler = debounce(() => {
    updateButtons();
}, 100);

const observeResize = () => {
    const el = pathRef.value as any;
    if (!el) return;
    resizeObserver = new ResizeObserver(() => {
        resizeHandler();
    });

    const ele = btnWrapper.value as any;
    if (!ele) return;
    resizeObserver = new ResizeObserver(() => {
        btnResizeHandler();
    });
    resizeObserver.observe(el);
    resizeObserver.observe(ele);
};

const resetPaths = () => {
    paths.value = [...hidePaths.value, ...paths.value];
    hidePaths.value = [];
};

const right = () => {
    if (pointer < history.length - 1) {
        pointer++;
        let url = history[pointer];
        backForwardJump(url);
    }
};

const back = () => {
    if (pointer > 0) {
        pointer--;
        let url = history[pointer];
        backForwardJump(url);
    }
};

const top = () => {
    if (paths.value.length > 0) {
        let url = '/';
        if (paths.value.length >= 2) {
            url = paths.value[paths.value.length - 2].url;
        }
        jump(url);
    }
};

const jump = async (url: string) => {
    history.splice(pointer + 1);
    history.push(url);
    pointer = history.length - 1;

    const { path: oldUrl, pageSize: oldPageSize } = req;
    Object.assign(req, initData(), { path: url, containSub: false, search: '', pageSize: oldPageSize });
    let searchResult = await searchFile();
    if (!searchResult.data.path) {
        req.path = oldUrl;
        globalStore.setLastFilePath(req.path);
        MsgWarning(i18n.global.t('commons.res.notFound'));
        return;
    }
    req.path = searchResult.data.path;
    globalStore.setLastFilePath(req.path);
    handleSearchResult(searchResult);
    getPaths(req.path);
    nextTick(function () {
        handlePath();
    });
};

const backForwardJump = async (url: string) => {
    const oldPageSize = req.pageSize;
    Object.assign(req, initData());
    req.path = url;
    req.containSub = false;
    req.search = '';
    req.pageSize = oldPageSize;
    let searchResult = await searchFile();
    handleSearchResult(searchResult);
    getPaths(req.path);
    nextTick(function () {
        handlePath();
    });
};

const getPaths = (reqPath: string) => {
    const pathArray = reqPath.split('/');
    paths.value = [];
    hidePaths.value = [];
    let base = '/';
    for (const p of pathArray) {
        if (p != '') {
            if (base.endsWith('/')) {
                base = base + p;
            } else {
                base = base + '/' + p;
            }
            paths.value.push({
                url: base,
                name: p,
            });
        }
    }
};

const handleCreate = (command: string) => {
    fileCreate.path = req.path;
    fileCreate.isDir = command === 'dir';
    createRef.value.acceptParams(fileCreate);
};

const delFile = async (row: File.File | null) => {
    deleteRef.value.acceptParams([row]);
};

const batchDelFiles = () => {
    deleteRef.value.acceptParams(selects.value);
};

const formatFileSize = (size: number) => {
    return computeSize(size);
};

const getFileSize = async (path: string) => {
    codeReq.path = path;
    codeReq.expand = true;
    codeReq.isDetail = true;
    updateByPath(path, { btnLoading: true });
    try {
        const res = await getFileContent(codeReq);
        updateByPath(path, { dirSize: res.data.size });
    } finally {
        updateByPath(path, { btnLoading: false });
    }
};

const getDirSize = async (path: string) => {
    const req = {
        path: path,
    };
    updateByPath(path, { btnLoading: true });
    try {
        const res = await computeDirSize(req);
        updateByPath(path, { dirSize: res.data.size });
    } finally {
        updateByPath(path, { btnLoading: false });
    }
};

const updateByPath = (path: string, patch: Partial<(typeof data.value)[0]>) => {
    data.value = data.value.map((item) => (item.path === path ? { ...item, ...patch } : item));
};

const getDirTotalSize = async (path: string) => {
    const req = {
        path: path,
    };
    calculateBtn.value = true;
    const res = await computeDirSize(req);
    dirTotalSize.value = res.data.size;
    calculateBtn.value = false;
};

const calculateSize = (path: string) => {
    const req = { path };
    disableBtn.value = true;
    setTimeout(async () => {
        try {
            const res = await computeDepthDirSize(req);
            const sizeMap = new Map(res.data.map((dir) => [dir.path, dir.size]));
            data.value.forEach((item) => {
                if (sizeMap.has(item.path)) {
                    item.dirSize = sizeMap.get(item.path)!;
                }
            });
        } catch (err) {
            console.error('Error computing dir size:', err);
        } finally {
            disableBtn.value = false;
        }
    }, 0);
};

const getIconName = (extension: string) => {
    return getIcon(extension);
};

const openMode = (item: File.File) => {
    roleRef.value.acceptParams(item);
};

const openChown = (item: File.File) => {
    chownRef.value.acceptParams(item);
};

const openCompress = (items: File.File[]) => {
    const paths = [];
    for (const item of items) {
        paths.push(item.path);
    }
    fileCompress.files = paths;
    if (paths.length === 1) {
        fileCompress.name = items[0].name;
    } else {
        fileCompress.name = getRandomStr(6);
    }
    fileCompress.dst = req.path;

    compressRef.value.acceptParams(fileCompress);
};

const openDeCompress = (item: File.File) => {
    if (Mimetypes.get(item.mimeType) == undefined) {
        MsgWarning(i18n.global.t('file.canNotDeCompress'));
        return;
    }

    if (CompressExtension[Mimetypes.get(item.mimeType)] != item.extension) {
        fileDeCompress.mimeType = MimetypeByExtensionObject[item.extension];
    } else {
        fileDeCompress.mimeType = item.mimeType;
    }

    fileDeCompress.name = item.name;
    fileDeCompress.path = item.path;
    fileDeCompress.dst = req.path;

    deCompressRef.value.acceptParams(fileDeCompress);
};

const openView = (item: File.File) => {
    const fileType = getFileType(item.extension);
    if (fileType === 'image') {
        imageFiles.value = data.value
            .filter((item) => !item.isDir)
            .filter((item) => getFileType(item.extension) == 'image')
            .map((item) => (item.isSymlink ? item.linkPath : item.path));
    }

    const previewTypes = ['image', 'video', 'audio', 'word', 'excel'];
    if (previewTypes.includes(fileType)) {
        return openPreview(item, fileType);
    }

    const actionMap = {
        compress: openDeCompress,
        text: () => openCodeEditor(item.path, item.extension),
    };

    const path = item.isSymlink ? item.linkPath : item.path;
    return actionMap[fileType] ? actionMap[fileType](item) : openCodeEditor(path, item.extension);
};

const openPreview = (item: File.File, fileType: string) => {
    if (item.mode.toString() == '-' && item.user == '-' && item.group == '-') {
        MsgWarning(i18n.global.t('file.fileCanNotRead'));
        return;
    }
    filePreview.path = item.isSymlink ? item.linkPath : item.path;
    filePreview.name = item.name;
    filePreview.extension = item.extension;
    filePreview.fileType = fileType;
    filePreview.imageFiles = imageFiles.value;
    filePreview.currentNode = globalStore.currentNode;

    previewRef.value.acceptParams(filePreview);
};

const openCodeEditor = (path: string, extension: string) => {
    codeReq.path = path;
    codeReq.expand = true;

    if (extension != '') {
        Languages.forEach((language) => {
            const ext = extension.substring(1);
            if (language.value.indexOf(ext) > -1) {
                fileEdit.language = language.label;
            }
        });
    }

    getFileContent(codeReq)
        .then((res) => {
            fileEdit.content = res.data.content;
            fileEdit.path = res.data.path;
            fileEdit.name = res.data.name;
            fileEdit.extension = res.data.extension;

            codeEditorRef.value.acceptParams(fileEdit);
        })
        .catch(() => {});
};

const openUpload = () => {
    fileUpload.path = req.path;
    uploadRef.value.acceptParams(fileUpload);
};

const openWget = () => {
    fileWget.path = req.path;
    wgetRef.value.acceptParams(fileWget);
};

const openBatchRole = (items: File.File[]) => {
    batchRoleRef.value.acceptParams({ files: items });
};

const closeWget = (submit: Boolean) => {
    search();
    if (submit) {
        openProcess();
    }
};

const closeMovePage = (submit: Boolean) => {
    if (submit) {
        search();
        closeMove();
    }
};

const openProcess = () => {
    processRef.value.acceptParams();
};

const closeProcess = () => {
    search();
    getWgetProcess();
    setTimeout(() => {
        getWgetProcess();
    }, 1000);
};

const processCount = ref(0);
const getWgetProcess = async () => {
    processCount.value = 0;
    try {
        const res = await fileWgetKeys();
        if (res.data && res.data.keys.length > 0) {
            processCount.value = res.data.keys.length;
        }
    } catch (error) {}
};

const openRename = (item: File.File) => {
    fileRename.path = req.path;
    fileRename.oldName = item.name;
    renameRef.value.acceptParams(fileRename);
};

const openMove = (type: string) => {
    fileMove.type = type;
    fileMove.name = '';
    fileMove.allNames = [];
    fileMove.isDir = false;
    const oldPaths = [];
    for (const s of selects.value) {
        oldPaths.push(s['path']);
    }
    fileMove.count = selects.value.length;
    fileMove.oldPaths = oldPaths;
    if (selects.value.length == 1) {
        fileMove.name = selects.value[0].name;
        fileMove.isDir = selects.value[0].isDir;
    } else {
        const allNames = [];
        for (const s of selects.value) {
            allNames.push(s['name']);
        }
        fileMove.allNames = allNames;
    }
    moveOpen.value = true;
};

const openMoveBtn = (type: string, item: File.File) => {
    selects.value = [];
    selects.value.push(item);
    openMove(type);
};

const closeMove = () => {
    selects.value = [];
    tableRef.value.clearSelects();
    fileMove.oldPaths = [];
    fileMove.name = '';
    fileMove.count = 0;
    fileMove.isDir = false;
    moveOpen.value = false;
};

const openPaste = () => {
    fileMove.path = req.path;
    moveRef.value.acceptParams(fileMove);
};

const openPasteBtn = (file: File.File) => {
    if (file.isDir) {
        fileMove.path = file.path;
    }
    moveRef.value.acceptParams(fileMove);
};

const openDownload = (file: File.File) => {
    downloadFile(file.path, globalStore.currentNode);
};

const openDetail = (row: File.File) => {
    detailRef.value.acceptParams({ path: row.path });
};

const openRecycleBin = () => {
    recycleBinRef.value.acceptParams();
};

const openFavorite = () => {
    favoriteRef.value.acceptParams();
};

const changeSort = ({ prop, order }) => {
    req.sortBy = prop;
    req.sortOrder = order;
    req.search = '';
    req.page = 1;
    req.pageSize = paginationConfig.pageSize;
    req.containSub = false;
    search();
};

const showFavorite = (row: File.File) => {
    hoveredRowPath.value = row.path;
};

const hideFavorite = () => {
    hoveredRowPath.value = null;
};

const addToFavorite = async (row: File.File) => {
    try {
        await addFavorite(row.path);
        await search();
    } catch (error) {}
};

const remove = async (id: number) => {
    ElMessageBox.confirm(i18n.global.t('file.removeFavorite'), i18n.global.t('commons.msg.remove'), {
        confirmButtonText: i18n.global.t('commons.button.confirm'),
        cancelButtonText: i18n.global.t('commons.button.cancel'),
    }).then(async () => {
        try {
            await removeFavorite(id);
            await search();
        } catch (error) {}
    });
};

const getFavorites = async () => {
    try {
        const res = await searchFavorite(req);
        favorites.value = res.data.items;
    } catch (error) {}
};

const toFavorite = (row: File.Favorite) => {
    if (row.isDir) {
        jump(row.path);
    } else {
        let file = {} as File.File;
        file.path = row.path;
        file.extension = '.' + row.name.split('.').pop();
        openView(file);
    }
};

const dialogTerminalRef = ref();
const toTerminal = () => {
    dialogTerminalRef.value!.acceptParams({ cwd: req.path, command: '/bin/sh' });
};

const openWithVSCode = (row: File.File) => {
    dialogVscodeOpenRef.value.acceptParams({ path: row.path + (row.isDir ? '' : ':1:1') });
};

const buttons = [
    {
        label: i18n.global.t('commons.button.open'),
        click: open,
    },
    {
        label: i18n.global.t('commons.button.download'),
        click: (row: File.File) => {
            openDownload(row);
        },
        disabled: (row: File.File) => {
            return row.isDir;
        },
    },
    {
        label: i18n.global.t('commons.button.copy'),
        click: (row: File.File) => openMoveBtn('copy', row),
    },
    {
        label: i18n.global.t('file.move'),
        click: (row: File.File) => openMoveBtn('cut', row),
    },
    {
        label: i18n.global.t('file.paste'),
        click: (row: File.File) => {
            openPasteBtn(row);
        },
        disabled: () => {
            return !moveOpen.value;
        },
    },
    {
        label: i18n.global.t('file.compress'),
        click: (row: File.File) => {
            openCompress([row]);
        },
    },
    {
        label: i18n.global.t('file.deCompress'),
        click: openDeCompress,
        disabled: (row: File.File) => {
            return !isDecompressFile(row);
        },
    },
    {
        label: i18n.global.t('file.editPermissions'),
        click: (row: File.File) => {
            openBatchRole([row]);
        },
    },
    {
        label: i18n.global.t('file.rename'),
        click: openRename,
    },
    {
        label: i18n.global.t('commons.button.delete'),
        disabled: (row: File.File) => {
            return row.name == '.1panel_clash';
        },
        click: delFile,
        divided: true,
    },
    {
        label: i18n.global.t('file.copyDir'),
        click: copyDir,
    },
    {
        label: i18n.global.t('file.addFavorite'),
        click: (row: File.File) => {
            if (row.favoriteID > 0) {
                remove(row.favoriteID);
            } else {
                addToFavorite(row);
            }
        },
    },
    {
        label: i18n.global.t('file.openWithVscode'),
        click: openWithVSCode,
    },
    {
        label: i18n.global.t('file.info'),
        click: openDetail,
        divided: true,
    },
];

const isDecompressFile = (row: File.File) => {
    if (row.isDir) {
        return false;
    }
    if (getFileType(row.extension) === 'compress') {
        return true;
    }
    if (row.mimeType == 'application/octet-stream') {
        return false;
    } else {
        return Mimetypes.get(row.mimeType) != undefined;
    }
};

const getHostMount = async () => {
    try {
        const res = await searchHostMount();
        hostMount.value = res.data;
    } catch (error) {
        console.error('Error fetching host mount:', error);
    }
};

onMounted(() => {
    if (localStorage.getItem('show-hidden') === null) {
        localStorage.setItem('show-hidden', 'true');
    }
    req.showHidden = localStorage.getItem('show-hidden') === 'true';
    getHostMount();
    if (router.currentRoute.value.query.path) {
        req.path = String(router.currentRoute.value.query.path);
        getPaths(req.path);
        globalStore.setLastFilePath(req.path);
    } else if (globalStore.lastFilePath && globalStore.lastFilePath != '') {
        req.path = globalStore.lastFilePath;
        getPaths(req.path);
    }
    pathWidth.value = pathRef.value.offsetWidth;
    search();
    history.push(req.path);
    pointer = history.length - 1;
    nextTick(function () {
        handlePath();
        observeResize();
    });
});

onBeforeUnmount(() => {
    if (resizeObserver) resizeObserver.disconnect();
});
</script>

<style scoped lang="scss">
.path {
    display: flex;
    align-items: center;
    border: 1px solid #ebeef5;
    background-color: var(--panel-path-bg);
    height: 30px;
    border-radius: 2px !important;
    &:hover {
        cursor: text;
        box-shadow: var(--el-box-shadow);
    }

    .root {
        vertical-align: middle;
        margin-left: 10px;
    }
    .other {
        vertical-align: middle;
    }
    .split {
        margin-left: 5px;
        margin-right: 5px;
    }
}

.copy-button {
    .close {
        width: 10px;
        .close-icon {
            color: red;
        }
    }
}

.btn-container {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
}

.favorite-item {
    height: 30vh;
    overflow: auto;
}

.file-row {
    display: flex;
    align-items: center;
    width: 100%;
}

.file-name {
    flex-grow: 1;
    margin-left: 1px;
    width: 95%;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
.address-bar {
    border: var(--el-border);
    .arrow {
        color: #726e6e;
    }
}
.search-button {
    width: 20vw;
}
.el-button-group > .el-dropdown > .el-button {
    border-left-color: var(--el-border-color);
}
</style>
