const API_URL = 'ajax.php';

const state = {
    currentFolderId: 'root',
    currentSection: 'all',
    path: [{ id: 'root', name: '全部文件' }],
    items: [],
    rootFolders: [],
    selectedItems: new Set(),
    selectionMode: false,
    searchQuery: '',
    sortBy: 'time-desc',
    contextMenuItemId: null,
    storage: null,
    uploadQueue: [],
    isUploading: false,
    isCreatingFolder: false,
    isChangingPassword: false,
    isEmptyingTrash: false,
    isFactoryResetting: false,
};

const fileMap = new Map();

document.addEventListener('DOMContentLoaded', init);

async function init() {
    setupEventListeners();
    renderBreadcrumb();
    renderFileList();

    try {
        const status = await api('status');
        if (!status.data.authenticated) {
            window.location.href = 'login.php';
            return;
        }

        await loadInitialFolder();
    } catch (error) {
        handleApiError(error);
    }
}

function setupEventListeners() {
    const searchInput = document.getElementById('search-input');
    searchInput.addEventListener('input', (event) => {
        state.searchQuery = event.target.value;
        document.getElementById('clear-search').classList.toggle('hidden', !event.target.value);
        renderFileList();
    });

    document.addEventListener('click', () => {
        document.getElementById('context-menu').classList.add('hidden');
    });

    document.addEventListener('keydown', (event) => {
        if (event.key === 'Escape') {
            closeAllModals();
            document.getElementById('context-menu').classList.add('hidden');
        }
        if (event.key === 'Enter' && !document.getElementById('new-folder-modal').classList.contains('hidden')) {
            createNewFolder();
        }
    });

    const dropZone = document.getElementById('main-content');
    dropZone.addEventListener('dragover', (event) => {
        event.preventDefault();
        dropZone.classList.add('drag-over');
    });
    dropZone.addEventListener('dragleave', () => {
        dropZone.classList.remove('drag-over');
    });
    dropZone.addEventListener('drop', (event) => {
        event.preventDefault();
        dropZone.classList.remove('drag-over');
        handleFileUpload(event.dataTransfer.files);
    });

    const uploadZone = document.getElementById('upload-zone');
    const uploadInput = document.getElementById('upload-file-input');
    if (uploadZone && uploadInput) {
        uploadZone.addEventListener('click', (event) => {
            if (event.target.closest('button')) {
                return;
            }
            uploadInput.click();
        });
        document.getElementById('upload-select-btn').addEventListener('click', () => uploadInput.click());
        uploadInput.addEventListener('change', (event) => {
            addFilesToUploadQueue(event.target.files);
            event.target.value = '';
        });
        uploadZone.addEventListener('dragover', (event) => {
            event.preventDefault();
            uploadZone.classList.add('drag-over');
        });
        uploadZone.addEventListener('dragleave', () => {
            uploadZone.classList.remove('drag-over');
        });
        uploadZone.addEventListener('drop', (event) => {
            event.preventDefault();
            uploadZone.classList.remove('drag-over');
            addFilesToUploadQueue(event.dataTransfer.files);
        });
    }

    window.addEventListener('popstate', () => {
        loadFolderFromUrl({ replaceUrl: true });
    });
}

async function api(action, payload = null, options = {}) {
    const query = new URLSearchParams({ action });
    if (options.query) {
        Object.entries(options.query).forEach(([key, value]) => query.set(key, value));
        delete options.query;
    }

    const fetchOptions = {
        method: payload ? 'POST' : 'GET',
        credentials: 'same-origin',
        headers: {},
    };

    if (payload instanceof FormData) {
        fetchOptions.body = payload;
    } else if (payload) {
        fetchOptions.headers['Content-Type'] = 'application/json';
        fetchOptions.body = JSON.stringify(payload);
    }

    const response = await fetch(`${API_URL}?${query.toString()}`, {
        ...fetchOptions,
        ...options,
    });

    const text = await response.text();
    let result;
    try {
        result = JSON.parse(text);
    } catch (error) {
        throw new Error(text ? `接口返回异常：${text.slice(0, 120)}` : '接口无响应');
    }

    if (!result.success) {
        const error = new Error(result.message || '请求失败');
        error.data = result.data || {};
        error.status = response.status;
        throw error;
    }

    return result;
}

function handleApiError(error) {
    if (error.data && error.data.code === 'UNAUTHENTICATED') {
        window.location.href = 'login.php';
        return;
    }
    if (error.data && error.data.code === 'NOT_INSTALLED') {
        window.location.href = '../install/';
        return;
    }
    showToast(error.message || '操作失败', 'error');
}

async function loadFolder(folderId = 'root', resetPath = false) {
    state.currentSection = 'all';
    state.currentFolderId = folderId;
    state.selectedItems.clear();
    state.selectionMode = false;
    updateSelectionBar();
    setLoading(true);

    try {
        const result = await api('list', null, {
            query: {
                section: 'all',
                parent_id: folderId,
            },
        });
        applyFiles(result.data.files || []);
        updateStorage(result.data.storage || null);

        if (folderId === 'root') {
            state.rootFolders = state.items.filter((item) => item.isFolder);
        }

        if (resetPath) {
            state.path = [{ id: 'root', name: '全部文件' }];
        }

        renderSidebar();
        renderBreadcrumb();
        renderFileList();
        updateNavHighlight();
    } catch (error) {
        handleApiError(error);
    } finally {
        setLoading(false);
    }
}

async function loadRootFolders() {
    const result = await api('list', null, {
        query: {
            section: 'all',
            parent_id: 'root',
        },
    });
    state.rootFolders = (result.data.files || []).map(normalizeFile).filter((item) => item.isFolder);
}

function folderIdFromUrl() {
    const params = new URLSearchParams(window.location.search);
    const folderId = params.get('folder');
    return folderId && /^\d+$/.test(folderId) ? folderId : 'root';
}

function updateFolderUrl(folderId, replace = false) {
    const url = new URL(window.location.href);
    if (folderId === 'root') {
        url.searchParams.delete('folder');
    } else {
        url.searchParams.set('folder', folderId);
    }

    const nextUrl = `${url.pathname}${url.search}${url.hash}`;
    if (nextUrl === `${window.location.pathname}${window.location.search}${window.location.hash}`) {
        return;
    }

    const method = replace ? 'replaceState' : 'pushState';
    window.history[method]({ folderId }, '', nextUrl);
}

async function loadFolderFromUrl({ replaceUrl = false } = {}) {
    const folderId = folderIdFromUrl();
    if (folderId === 'root') {
        state.path = [{ id: 'root', name: '全部文件' }];
        await loadFolder('root', false);
        updateFolderUrl('root', replaceUrl);
        return;
    }

    try {
        const result = await api('folder_path', null, {
            query: {
                id: folderId,
            },
        });
        state.path = result.data.path || [{ id: 'root', name: '全部文件' }];
        await loadFolder(folderId, false);
        updateFolderUrl(folderId, replaceUrl);
    } catch (error) {
        state.path = [{ id: 'root', name: '全部文件' }];
        await loadFolder('root', false);
        updateFolderUrl('root', true);
        handleApiError(error);
    }
}

async function loadInitialFolder() {
    await loadRootFolders();
    await loadFolderFromUrl({ replaceUrl: true });
}

function applyFiles(files) {
    fileMap.clear();
    state.items = files.map(normalizeFile);
    state.items.forEach((item) => fileMap.set(item.id, item));
}

function normalizeFile(file) {
    const id = String(file.id);
    const parentId = file.path === 'root' || file.path === null ? 'root' : String(file.path);

    return {
        id,
        apiId: Number(file.id),
        name: file.name,
        type: file.type,
        isFolder: file.type === 'folder',
        parentId,
        size: Number(file.bytes || 0),
        sizeText: file.size || '0 B',
        modified: file.date || '',
        starred: Boolean(file.starred),
        shared: Boolean(file.shared),
        ext: file.ext || '',
    };
}

function setLoading(loading) {
    const fileList = document.getElementById('file-list');
    if (loading) {
        fileList.innerHTML = `
            <div class="py-16 text-center text-gray-400">
                <i class="ri-loader-4-line text-3xl animate-spin inline-block mb-3"></i>
                <p>正在加载...</p>
            </div>
        `;
    }
}

function updateStorage(storage) {
    state.storage = storage;
    if (!storage) {
        document.getElementById('storage-text').textContent = '0 B / 0 B';
        document.getElementById('storage-bar').style.width = '0%';
        return;
    }

    const remainingText = storage.remaining_text || storage.quota_text || '0 B';
    const totalText = storage.total_text || storage.quota_text || '0 B';
    document.getElementById('storage-text').textContent = `${remainingText} / ${totalText}`;
    document.getElementById('storage-bar').style.width = `${storage.percent}%`;
}

function renderSidebar() {
    const sidebar = document.getElementById('sidebar-folders');
    if (state.rootFolders.length === 0) {
        sidebar.innerHTML = '<div class="px-3 py-2 text-sm text-gray-400">暂无文件夹</div>';
        return;
    }

    sidebar.innerHTML = state.rootFolders.map((folder) => {
        const isActive = state.currentFolderId === folder.id;
        const activeClass = isActive ? 'bg-blue-50 text-blue-600 font-medium' : 'text-gray-600 hover:bg-gray-50';
        return `
            <div class="folder-item flex items-center gap-2 px-3 py-2 rounded-lg cursor-pointer ${activeClass}"
                 onclick="navigateTo('${folder.id}')">
                <i class="ri-folder-fill ${isActive ? 'text-blue-500' : 'text-yellow-500'}"></i>
                <span class="truncate">${escapeHtml(folder.name)}</span>
            </div>
        `;
    }).join('');
}

function renderBreadcrumb() {
    const breadcrumb = document.getElementById('breadcrumb');
    const backBtn = document.getElementById('back-btn');

    backBtn.disabled = state.path.length <= 1;
    breadcrumb.innerHTML = state.path.map((item, index) => {
        const isLast = index === state.path.length - 1;
        const icon = index === 0 ? '<i class="ri-home-5-line text-gray-400"></i>' : '<i class="ri-folder-3-line text-gray-400"></i>';
        const separator = isLast ? '' : '<i class="ri-arrow-right-s-line text-gray-300"></i>';
        const label = escapeHtml(item.name);

        if (isLast) {
            return `
                <span class="inline-flex items-center gap-1.5 text-gray-800 font-medium min-w-0">
                    ${icon}
                    <span class="truncate max-w-[220px]">${label}</span>
                </span>
            `;
        }

        return `
            <button class="inline-flex items-center gap-1.5 text-gray-500 hover:text-gray-800 transition-colors min-w-0" onclick="navigateToPath(${index})" type="button">
                ${icon}
                <span class="truncate max-w-[180px]">${label}</span>
            </button>
            ${separator}
        `;
    }).join('');
}

function renderFileList() {
    let items = [...state.items];

    if (state.searchQuery) {
        const keyword = state.searchQuery.toLowerCase();
        items = items.filter((item) => item.name.toLowerCase().includes(keyword));
    }

    sortItems(items);

    document.getElementById('search-empty').classList.toggle('hidden', !state.searchQuery || items.length > 0);
    document.getElementById('empty-state').classList.toggle('hidden', items.length > 0 || Boolean(state.searchQuery));
    document.getElementById('file-list').parentElement.classList.toggle('hidden', state.searchQuery && items.length === 0);

    renderListView(items);
    updateSelectAllCheckbox(items);
}

function updateSelectionModeUi() {
    const selectAllCol = document.getElementById('select-all-col');
    const fileNameHeader = document.getElementById('file-name-header');
    const batchSelectBtn = document.getElementById('batch-select-btn');

    selectAllCol.classList.toggle('hidden', !state.selectionMode);
    selectAllCol.classList.toggle('flex', state.selectionMode);
    fileNameHeader.className = state.selectionMode ? 'col-span-5' : 'col-span-6';
    batchSelectBtn.innerHTML = state.selectionMode
        ? '<i class="ri-close-line"></i> <span class="hidden sm:inline">取消批量</span><span class="sm:hidden">取消</span>'
        : '<i class="ri-checkbox-multiple-line"></i> <span class="hidden sm:inline">批量选择</span><span class="sm:hidden">批量</span>';
}

function renderListView(items) {
    const fileList = document.getElementById('file-list');
    updateSelectionModeUi();

    if (items.length === 0) {
        fileList.innerHTML = '';
        return;
    }

    fileList.innerHTML = items.map((item) => {
        const isSelected = state.selectedItems.has(item.id);
        return `
            <div class="file-item file-row flex md:grid md:grid-cols-12 gap-3 md:gap-4 px-4 py-3 border-b border-gray-100 items-start md:items-center ${isSelected ? 'selected' : ''}"
                 data-id="${item.id}"
                 ondblclick="handleItemDoubleClick(event, '${item.id}')"
                 onclick="handleItemClick(event, '${item.id}')"
                 oncontextmenu="showContextMenu(event, '${item.id}')">
                <div class="${state.selectionMode ? 'w-5 md:w-auto md:col-span-1 pt-1 md:pt-0' : 'hidden'}">
                    <input type="checkbox" ${isSelected ? 'checked' : ''}
                           onclick="event.stopPropagation(); toggleSelection('${item.id}')"
                           class="w-4 h-4 rounded">
                </div>
                <div class="${state.selectionMode ? 'md:col-span-5' : 'md:col-span-6'} flex-1 md:flex-none min-w-0">
                    <div class="flex items-center gap-3 min-w-0">
                        ${getFileIcon(item)}
                        <span class="text-gray-800 truncate">${highlightSearch(item.name)}</span>
                        ${item.starred ? '<i class="ri-star-fill text-yellow-400 flex-shrink-0"></i>' : ''}
                    </div>
                    <div class="mt-1 flex items-center gap-2 text-xs text-gray-500 md:hidden">
                        <span>${item.isFolder ? '文件夹' : item.sizeText}</span>
                        <span class="text-gray-300">/</span>
                        <span>${escapeHtml(item.modified)}</span>
                    </div>
                </div>
                <div class="hidden md:block col-span-2 text-gray-500 text-sm">${item.isFolder ? '-' : item.sizeText}</div>
                <div class="hidden md:block col-span-3 text-gray-500 text-sm">${escapeHtml(item.modified)}</div>
                <div class="w-20 flex-shrink-0 md:w-auto md:col-span-1 flex justify-end gap-1">
                    <button class="p-1.5 hover:bg-gray-100 rounded text-gray-400 hover:text-gray-600"
                            onclick="event.stopPropagation(); downloadItem('${item.id}')" title="下载">
                        <i class="ri-download-line"></i>
                    </button>
                    <button class="p-1.5 hover:bg-gray-100 rounded text-gray-400 hover:text-gray-600"
                            onclick="event.stopPropagation(); showMoreMenu(event, '${item.id}')" title="更多">
                        <i class="ri-more-2-fill"></i>
                    </button>
                </div>
            </div>
        `;
    }).join('');
}

function getFileIcon(item) {
    if (item.isFolder) {
        return '<i class="ri-folder-fill text-yellow-500 text-xl"></i>';
    }

    const ext = (item.ext || item.name.split('.').pop() || '').toLowerCase();
    const iconMap = {
        doc: 'ri-file-word-fill text-blue-500',
        docx: 'ri-file-word-fill text-blue-500',
        pdf: 'ri-file-pdf-fill text-red-500',
        xls: 'ri-file-excel-fill text-green-500',
        xlsx: 'ri-file-excel-fill text-green-500',
        ppt: 'ri-file-ppt-fill text-orange-500',
        pptx: 'ri-file-ppt-fill text-orange-500',
        jpg: 'ri-image-fill text-purple-500',
        jpeg: 'ri-image-fill text-purple-500',
        png: 'ri-image-fill text-purple-500',
        gif: 'ri-image-fill text-purple-500',
        webp: 'ri-image-fill text-purple-500',
        mp4: 'ri-video-fill text-pink-500',
        avi: 'ri-video-fill text-pink-500',
        mov: 'ri-video-fill text-pink-500',
        mp3: 'ri-music-fill text-cyan-500',
        wav: 'ri-music-fill text-cyan-500',
        zip: 'ri-file-zip-fill text-gray-500',
        rar: 'ri-file-zip-fill text-gray-500',
        txt: 'ri-file-text-fill text-gray-500',
        md: 'ri-file-markdown-fill text-gray-600',
    };

    return `<i class="${iconMap[ext] || 'ri-file-fill text-gray-400'} text-xl"></i>`;
}

function sortItems(items) {
    const [field, order] = state.sortBy.split('-');
    const multiplier = order === 'asc' ? 1 : -1;

    items.sort((a, b) => {
        if (a.isFolder !== b.isFolder) {
            return a.isFolder ? -1 : 1;
        }
        if (field === 'name') {
            return multiplier * a.name.localeCompare(b.name, 'zh-CN');
        }
        if (field === 'size') {
            return multiplier * (a.size - b.size);
        }
        if (field === 'time') {
            return multiplier * (new Date(a.modified) - new Date(b.modified));
        }
        return 0;
    });
}

async function navigateTo(folderId) {
    if (folderId === 'root') {
        state.path = [{ id: 'root', name: '全部文件' }];
        await loadFolder('root');
        updateFolderUrl('root');
        return;
    }

    const folder = fileMap.get(String(folderId)) || state.rootFolders.find((item) => item.id === String(folderId));
    if (!folder || !folder.isFolder) {
        return;
    }

    const existingIndex = state.path.findIndex((item) => item.id === folder.id);
    if (existingIndex >= 0) {
        state.path = state.path.slice(0, existingIndex + 1);
    } else {
        state.path.push({ id: folder.id, name: folder.name });
    }

    await loadFolder(folder.id);
    updateFolderUrl(folder.id);
}

async function navigateToPath(index) {
    const target = state.path[index];
    if (!target) {
        return;
    }
    state.path = state.path.slice(0, index + 1);
    await loadFolder(target.id);
    updateFolderUrl(target.id);
}

async function goBack() {
    if (state.path.length <= 1) {
        return;
    }
    state.path.pop();
    const parent = state.path[state.path.length - 1];
    await loadFolder(parent.id);
    updateFolderUrl(parent.id);
}

function updateNavHighlight() {
    const all = document.getElementById('nav-all');
    const recent = document.getElementById('nav-recent');

    [all, recent].forEach((el) => {
        el.classList.remove('bg-blue-50', 'text-blue-600', 'font-medium');
        el.classList.add('text-gray-600');
    });

    const active = state.currentSection === 'recent' ? recent : all;
    active.classList.add('bg-blue-50', 'text-blue-600', 'font-medium');
    active.classList.remove('text-gray-600');
}

function handleItemClick(event, itemId) {
    if (event.ctrlKey || event.metaKey) {
        state.selectionMode = true;
        toggleSelection(itemId);
    }
}

function handleItemDoubleClick(event, itemId) {
    event.preventDefault();
    const selection = window.getSelection();
    if (selection) {
        selection.removeAllRanges();
    }

    openItem(itemId);
}

function openItem(itemId) {
    const item = fileMap.get(itemId);
    if (!item) {
        return;
    }
    if (item.isFolder) {
        navigateTo(itemId);
    } else {
        downloadItem(itemId);
    }
}

function toggleSelection(itemId) {
    state.selectionMode = true;
    if (state.selectedItems.has(itemId)) {
        state.selectedItems.delete(itemId);
    } else {
        state.selectedItems.add(itemId);
    }
    updateSelectionBar();
    renderFileList();
}

function toggleSelectAll() {
    state.selectionMode = true;
    const visibleIds = visibleItems().map((item) => item.id);
    if (visibleIds.length > 0 && visibleIds.every((id) => state.selectedItems.has(id))) {
        visibleIds.forEach((id) => state.selectedItems.delete(id));
    } else {
        visibleIds.forEach((id) => state.selectedItems.add(id));
    }
    updateSelectionBar();
    renderFileList();
}

function toggleSelectionMode() {
    state.selectionMode = !state.selectionMode;
    if (!state.selectionMode) {
        state.selectedItems.clear();
    }
    updateSelectionBar();
    renderFileList();
}

function visibleItems() {
    let items = [...state.items];
    if (state.searchQuery) {
        const keyword = state.searchQuery.toLowerCase();
        items = items.filter((item) => item.name.toLowerCase().includes(keyword));
    }
    return items;
}

function clearSelection() {
    state.selectedItems.clear();
    state.selectionMode = false;
    updateSelectionBar();
    renderFileList();
}

function updateSelectionBar() {
    const bar = document.getElementById('selection-bar');
    const count = document.getElementById('selected-count');

    count.textContent = String(state.selectedItems.size);
    bar.classList.toggle('hidden', !state.selectionMode);
    bar.classList.toggle('flex', state.selectionMode);
}

function updateSelectAllCheckbox(items = visibleItems()) {
    const checkbox = document.getElementById('select-all');
    if (!checkbox) {
        return;
    }
    const ids = items.map((item) => item.id);
    checkbox.checked = ids.length > 0 && ids.every((id) => state.selectedItems.has(id));
    checkbox.indeterminate = ids.some((id) => state.selectedItems.has(id)) && !checkbox.checked;
}

function sortFiles() {
    state.sortBy = document.getElementById('sort-select').value;
    renderFileList();
}

function clearSearch() {
    document.getElementById('search-input').value = '';
    state.searchQuery = '';
    document.getElementById('clear-search').classList.add('hidden');
    renderFileList();
}

function showContextMenu(event, itemId) {
    event.preventDefault();
    event.stopPropagation();

    state.contextMenuItemId = itemId;
    const menu = document.getElementById('context-menu');

    menu.style.left = `${event.clientX}px`;
    menu.style.top = `${event.clientY}px`;
    menu.classList.remove('hidden');
}

function showMoreMenu(event, itemId) {
    event.preventDefault();
    event.stopPropagation();

    state.contextMenuItemId = itemId;
    const menu = document.getElementById('context-menu');
    const rect = event.currentTarget.getBoundingClientRect();

    menu.style.left = `${rect.left}px`;
    menu.style.top = `${rect.bottom + 4}px`;
    menu.classList.remove('hidden');
}

function handleContextAction(action) {
    const itemId = state.contextMenuItemId;
    document.getElementById('context-menu').classList.add('hidden');

    if (!itemId) {
        return;
    }

    if (action === 'open') {
        openItem(itemId);
    } else if (action === 'download') {
        downloadItem(itemId);
    } else if (action === 'rename') {
        startRename(itemId);
    } else if (action === 'delete') {
        deleteItem(itemId);
    }
}

function downloadItem(itemId) {
    const item = fileMap.get(itemId);
    if (!item) {
        return;
    }
    if (item.isFolder) {
        showToast('文件夹暂不支持下载', 'error');
        return;
    }
    window.location.href = `${API_URL}?action=download&id=${encodeURIComponent(item.apiId)}`;
}

function downloadSelected() {
    const selected = [...state.selectedItems].map((id) => fileMap.get(id)).filter(Boolean);
    const files = selected.filter((item) => !item.isFolder);

    if (files.length === 0) {
        showToast('请选择文件下载，文件夹暂不支持下载', 'error');
        return;
    }

    files.forEach((item, index) => {
        setTimeout(() => downloadItem(item.id), index * 300);
    });
}

function startRename(itemId) {
    const item = fileMap.get(itemId);
    if (!item) {
        return;
    }

    document.getElementById('rename-input').value = item.name;
    state.contextMenuItemId = itemId;
    openModal('rename-modal');
    setTimeout(() => document.getElementById('rename-input').focus(), 50);
}

async function confirmRename() {
    const item = fileMap.get(state.contextMenuItemId);
    const newName = document.getElementById('rename-input').value.trim();

    if (!item || !newName) {
        showToast('请输入有效名称', 'error');
        return;
    }

    try {
        await api('rename', { id: item.apiId, name: newName });
        closeModal('rename-modal');
        await refreshCurrentFolder();
        showToast('重命名成功');
    } catch (error) {
        handleApiError(error);
    }
}

async function changePassword(event) {
    event.preventDefault();
    if (state.isChangingPassword) {
        return;
    }

    const currentPassword = document.getElementById('current-password').value;
    const newPassword = document.getElementById('new-password').value;
    const confirmPassword = document.getElementById('confirm-password').value;

    if (!currentPassword || !newPassword || !confirmPassword) {
        showToast('请完整填写密码', 'error');
        return;
    }
    if (newPassword.length < 6) {
        showToast('新密码至少需要 6 位', 'error');
        return;
    }
    if (newPassword !== confirmPassword) {
        showToast('两次输入的新密码不一致', 'error');
        return;
    }

    const button = document.getElementById('change-password-btn');
    state.isChangingPassword = true;
    button.disabled = true;
    button.textContent = '保存中...';

    try {
        await api('change_password', {
            current_password: currentPassword,
            new_password: newPassword,
            confirm_password: confirmPassword,
        });
        closeModal('settings-modal');
        showToast('密码修改成功');
    } catch (error) {
        handleApiError(error);
    } finally {
        state.isChangingPassword = false;
        button.disabled = false;
        button.textContent = '保存';
    }
}

function switchSettingsTab(tab) {
    const activeClass = 'px-4 py-2 text-sm rounded-t-lg bg-blue-50 text-blue-600 font-medium';
    const inactiveClass = 'px-4 py-2 text-sm rounded-t-lg text-gray-600 hover:bg-gray-50';
    const tabs = ['account', 'maintenance', 'factory', 'about'];

    tabs.forEach((name) => {
        document.getElementById(`settings-${name}-tab`).className = tab === name ? activeClass : inactiveClass;
        document.getElementById(`settings-${name}-panel`).classList.toggle('hidden', tab !== name);
    });

    if (tab === 'maintenance') {
        loadMaintenanceStats();
    }
}

async function factoryReset(event) {
    event.preventDefault();
    if (state.isFactoryResetting) {
        return;
    }

    const password = document.getElementById('factory-password').value;
    if (!password) {
        showToast('请输入登录密码', 'error');
        return;
    }
    if (!confirm('确定恢复出厂设置吗？所有数据、配置和上传文件都会被删除。')) {
        return;
    }

    const button = document.getElementById('factory-reset-btn');
    state.isFactoryResetting = true;
    button.disabled = true;
    button.textContent = '恢复中...';

    try {
        const result = await api('factory_reset', { password });
        showToast('已恢复出厂设置');
        window.location.href = result.data.redirect || '../install/';
    } catch (error) {
        handleApiError(error);
        state.isFactoryResetting = false;
        button.disabled = false;
        button.textContent = '确认恢复出厂';
    }
}

async function loadMaintenanceStats() {
    const loading = document.getElementById('maintenance-loading');
    const content = document.getElementById('maintenance-content');
    loading.classList.remove('hidden');
    content.classList.add('hidden');

    try {
        const result = await api('maintenance_stats');
        renderMaintenanceStats(result.data.stats || {});
    } catch (error) {
        handleApiError(error);
    } finally {
        loading.classList.add('hidden');
        content.classList.remove('hidden');
    }
}

function renderMaintenanceStats(stats) {
    document.getElementById('maint-file-count').textContent = String(stats.active_file_count ?? 0);
    document.getElementById('maint-folder-count').textContent = String(stats.active_folder_count ?? 0);
    document.getElementById('maint-trash-count').textContent = String(stats.trash_item_count ?? 0);
    document.getElementById('maint-trash-size').textContent = stats.trash_size_text || '0 B';
    document.getElementById('maint-used-size').textContent = stats.used_size_text || '0 B';
    document.getElementById('maint-db-size').textContent = stats.db_size_text || '0 B';

    const emptyTrashButton = document.getElementById('empty-trash-btn');
    emptyTrashButton.disabled = Number(stats.trash_item_count || 0) === 0;
}

async function emptyTrash() {
    if (state.isEmptyingTrash) {
        return;
    }
    if (!confirm('确定要永久清空回收站吗？此操作不可恢复。')) {
        return;
    }

    const button = document.getElementById('empty-trash-btn');
    state.isEmptyingTrash = true;
    button.disabled = true;
    button.textContent = '清理中...';
    let keepDisabled = false;

    try {
        const result = await api('empty_trash', {});
        const stats = result.data.stats || {};
        renderMaintenanceStats(stats);
        keepDisabled = Number(stats.trash_item_count || 0) === 0;
        updateStorage(result.data.storage || null);
        await refreshCurrentFolder();
        showToast(result.message || '回收站已清空');
    } catch (error) {
        handleApiError(error);
    } finally {
        state.isEmptyingTrash = false;
        button.innerHTML = '<i class="ri-delete-bin-6-line mr-1"></i> 清空回收站';
        button.disabled = keepDisabled;
    }
}

async function deleteItem(itemId) {
    const item = fileMap.get(itemId);
    if (!item) {
        return;
    }
    if (!confirm(`确定要删除「${item.name}」吗？`)) {
        return;
    }

    try {
        await api('delete', { ids: [item.apiId] });
        state.selectedItems.delete(itemId);
        if (state.selectedItems.size === 0) {
            state.selectionMode = false;
        }
        updateSelectionBar();
        await refreshCurrentFolder();
        showToast('已删除到回收站');
    } catch (error) {
        handleApiError(error);
    }
}

async function deleteSelected() {
    const selected = [...state.selectedItems].map((id) => fileMap.get(id)).filter(Boolean);
    if (selected.length === 0) {
        return;
    }
    if (!confirm(`确定要删除选中的 ${selected.length} 个项目吗？`)) {
        return;
    }

    try {
        await api('delete', { ids: selected.map((item) => item.apiId) });
        state.selectedItems.clear();
        state.selectionMode = false;
        updateSelectionBar();
        await refreshCurrentFolder();
        showToast(`已删除 ${selected.length} 个项目`);
    } catch (error) {
        handleApiError(error);
    }
}

async function createNewFolder() {
    if (state.isCreatingFolder) {
        return;
    }

    const input = document.getElementById('new-folder-name');
    const name = input.value.trim();

    if (!name) {
        showToast('请输入文件夹名称', 'error');
        return;
    }

    const duplicate = state.currentSection === 'all'
        && state.items.some((item) => item.isFolder && item.name === name);
    if (duplicate) {
        showToast('当前位置已存在同名文件夹', 'error');
        return;
    }

    state.isCreatingFolder = true;
    try {
        await api('create_folder', {
            name,
            parent_id: state.currentFolderId,
        });
        input.value = '';
        closeModal('new-folder-modal');
        await refreshCurrentFolder();
        showToast('文件夹创建成功');
    } catch (error) {
        handleApiError(error);
    } finally {
        state.isCreatingFolder = false;
    }
}

function formatSize(bytes) {
    if (bytes <= 0) {
        return '0 B';
    }

    const units = ['B', 'KB', 'MB', 'GB', 'TB'];
    const index = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
    const value = bytes / Math.pow(1024, index);
    return `${Number(value.toFixed(value >= 10 || index === 0 ? 0 : 1))} ${units[index]}`;
}

function uploadIconClass(file) {
    const ext = (file.name.split('.').pop() || '').toLowerCase();
    if (['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'svg'].includes(ext)) {
        return 'ri-image-line text-purple-500';
    }
    if (['mp4', 'avi', 'mov', 'mkv', 'webm', 'flv'].includes(ext)) {
        return 'ri-video-line text-pink-500';
    }
    if (['mp3', 'wav', 'flac', 'aac', 'ogg'].includes(ext)) {
        return 'ri-music-line text-cyan-500';
    }
    if (['zip', 'rar', '7z', 'tar', 'gz'].includes(ext)) {
        return 'ri-file-zip-line text-gray-500';
    }
    return 'ri-file-text-line text-blue-500';
}

function addFilesToUploadQueue(fileList) {
    const files = Array.from(fileList || []);
    if (files.length === 0) {
        return;
    }

    files.forEach((file) => {
        state.uploadQueue.push({
            id: `upload-${Date.now()}-${Math.random().toString(36).slice(2)}`,
            file,
            progress: 0,
            status: 'pending',
        });
    });
    renderUploadQueue();
}

function renderUploadQueue() {
    const list = document.getElementById('upload-list');
    const startBtn = document.getElementById('upload-start-btn');
    const clearBtn = document.getElementById('upload-clear-btn');
    if (!list || !startBtn || !clearBtn) {
        return;
    }

    const uploadableCount = state.uploadQueue.filter((item) => item.status !== 'done').length;
    startBtn.disabled = state.isUploading || uploadableCount === 0;
    clearBtn.disabled = state.isUploading || state.uploadQueue.length === 0;

    if (state.uploadQueue.length === 0) {
        list.innerHTML = '<div class="text-center text-sm text-gray-400 py-2">尚未选择文件</div>';
        return;
    }

    list.innerHTML = state.uploadQueue.map((item) => {
        const statusText = item.status === 'done' ? '完成' : item.status === 'error' ? '失败' : item.status === 'uploading' ? `${item.progress}%` : '等待';
        const barClass = item.status === 'error' ? 'bg-red-500' : item.status === 'done' ? 'bg-green-500' : 'bg-blue-500';
        return `
            <div class="flex items-center gap-3 p-3 bg-gray-50 rounded-lg">
                <i class="${uploadIconClass(item.file)} text-xl"></i>
                <div class="flex-1 min-w-0">
                    <div class="flex items-center justify-between gap-3">
                        <div class="text-sm font-medium text-gray-700 truncate">${escapeHtml(item.file.name)}</div>
                        <div class="text-xs text-gray-500 flex-shrink-0">${escapeHtml(statusText)}</div>
                    </div>
                    <div class="text-xs text-gray-400 mt-0.5">${formatSize(item.file.size)}</div>
                    <div class="w-full h-1.5 bg-gray-200 rounded-full mt-2 overflow-hidden">
                        <div class="h-full ${barClass} rounded-full transition-all duration-200" style="width: ${item.progress}%"></div>
                    </div>
                </div>
                <button class="p-1.5 hover:bg-gray-200 rounded text-gray-400 hover:text-red-500 ${state.isUploading ? 'hidden' : ''}"
                        onclick="removeQueuedUpload('${item.id}')" type="button" title="移除">
                    <i class="ri-close-line"></i>
                </button>
            </div>
        `;
    }).join('');
}

function removeQueuedUpload(id) {
    if (state.isUploading) {
        return;
    }
    state.uploadQueue = state.uploadQueue.filter((item) => item.id !== id);
    renderUploadQueue();
}

function clearUploadQueue() {
    if (state.isUploading) {
        return;
    }
    state.uploadQueue = [];
    renderUploadQueue();
}

function openUploadModal() {
    openModal('upload-modal');
    renderUploadQueue();
}

function closeUploadModal() {
    if (state.isUploading) {
        return;
    }
    closeModal('upload-modal');
}

function uploadQueuedItem(item) {
    const formData = new FormData();
    formData.append('parent_id', state.currentFolderId);
    formData.append('files[]', item.file);

    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open('POST', `${API_URL}?action=upload`);
        xhr.withCredentials = true;

        xhr.upload.addEventListener('progress', (event) => {
            if (!event.lengthComputable) {
                return;
            }
            item.progress = Math.min(99, Math.round((event.loaded / event.total) * 100));
            renderUploadQueue();
        });

        xhr.addEventListener('load', () => {
            let result;
            try {
                result = JSON.parse(xhr.responseText || '{}');
            } catch (error) {
                reject(new Error(xhr.responseText ? `接口返回异常：${xhr.responseText.slice(0, 120)}` : '接口无响应'));
                return;
            }

            if (!result.success) {
                const error = new Error(result.message || '上传失败');
                error.data = result.data || {};
                error.status = xhr.status;
                reject(error);
                return;
            }

            item.progress = 100;
            item.status = 'done';
            renderUploadQueue();
            resolve(result);
        });

        xhr.addEventListener('error', () => reject(new Error('网络异常，上传失败')));
        xhr.addEventListener('abort', () => reject(new Error('上传已取消')));

        item.status = 'uploading';
        item.progress = 0;
        renderUploadQueue();
        xhr.send(formData);
    });
}

async function startQueuedUpload() {
    if (state.isUploading || state.uploadQueue.length === 0) {
        return;
    }

    state.isUploading = true;
    renderUploadQueue();

    let successCount = 0;
    const pendingItems = state.uploadQueue.filter((item) => item.status !== 'done');
    for (const item of pendingItems) {
        try {
            await uploadQueuedItem(item);
            successCount += 1;
        } catch (error) {
            item.status = 'error';
            item.progress = 100;
            item.error = error.message || '上传失败';
            renderUploadQueue();
            handleApiError(error);
        }
    }

    state.isUploading = false;
    await refreshCurrentFolder();
    renderUploadQueue();

    if (successCount > 0) {
        showToast(`成功上传 ${successCount} 个文件`);
    }
}

async function handleFileUpload(fileList) {
    addFilesToUploadQueue(fileList);
    await startQueuedUpload();
}

async function refreshCurrentFolder() {
    if (state.currentFolderId === 'root') {
        await loadFolder('root');
        return;
    }
    await loadFolder(state.currentFolderId);
}

function openModal(id) {
    const modal = document.getElementById(id);
    modal.classList.remove('hidden');
    modal.classList.add('flex');
    modal.onclick = (event) => {
        if (event.target !== modal) {
            return;
        }
        if (id === 'upload-modal') {
            closeUploadModal();
            return;
        }
        closeModal(id);
    };

    if (id === 'new-folder-modal') {
        setTimeout(() => document.getElementById('new-folder-name').focus(), 50);
    } else if (id === 'settings-modal') {
        switchSettingsTab('account');
        setTimeout(() => document.getElementById('current-password').focus(), 50);
    }
}

function closeModal(id) {
    const modal = document.getElementById(id);
    modal.classList.add('hidden');
    modal.classList.remove('flex');

    if (id === 'settings-modal') {
        ['current-password', 'new-password', 'confirm-password', 'factory-password'].forEach((fieldId) => {
            document.getElementById(fieldId).value = '';
        });
    }
}

function closeAllModals() {
    if (state.isUploading) {
        return;
    }
    ['new-folder-modal', 'rename-modal', 'upload-modal', 'settings-modal'].forEach(closeModal);
}

function showToast(message, type = 'success') {
    const container = document.getElementById('toast-container');
    const toast = document.createElement('div');
    const colors = {
        success: 'bg-green-500',
        error: 'bg-red-500',
        info: 'bg-blue-500',
    };
    const icons = {
        success: 'ri-check-line',
        error: 'ri-error-warning-line',
        info: 'ri-information-line',
    };

    toast.className = `toast ${colors[type] || colors.success} text-white px-4 py-3 rounded-lg shadow-lg flex items-center gap-2`;
    toast.innerHTML = `<i class="${icons[type] || icons.success}"></i><span>${escapeHtml(message)}</span>`;
    container.appendChild(toast);

    setTimeout(() => toast.remove(), 3000);
}

function highlightSearch(name) {
    const escapedName = escapeHtml(name);
    if (!state.searchQuery) {
        return escapedName;
    }

    const escapedKeyword = escapeRegExp(state.searchQuery);
    return escapedName.replace(new RegExp(`(${escapedKeyword})`, 'gi'), '<mark class="bg-yellow-200">$1</mark>');
}

function escapeHtml(value) {
    return String(value)
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#039;');
}

function escapeRegExp(value) {
    return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
