// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtWebChannel 1.15
import Qt.labs.platform 1.1  // 提供Qt5/Qt6兼容的FileDialog
import "../dialog/"
import "../drag/"
import VNote 1.0
import org.deepin.dtk 1.0

Item {
    id: rootItem

    property bool isDragging: false
    property bool isPlay: false
    property bool isRecordingAudio: false
    property bool isSearch: false
    property bool isSearching: false
    property bool isVoiceToText: false
    property int itemSpacing: 6
    property alias model: itemModel
    property alias moveToFolderDialog: dialogWindow
    property var sourceFolderModel
    property int currentFolderIndex: -1
    property var saveFilters: ["TXT(*.txt);;HTML(*.html)", "TXT(*.txt)", "HTML(*.html)", "MP3(*.mp3)"]
    property alias searchLoader: noSearchResultsLoader
    property int selectSize: 0
    property var selectedNoteItem: []
    property int topSize: 0
    property alias view: itemListView
    property bool webVisible: true
    property Item scrollBarParent: null
    property int scrollBarRightAnchor: 0

    signal deleteFinished
    signal deleteNotes(int number)
    signal dropRelease
    signal emptyItemList
    signal mouseChanged(int mousePosX, int mousePosY)
    signal mulChoices(int choices)
    signal noteItemChanged(int index)

    function changeCurrentIndex(index) {
        itemListView.currentIndex = index;
    }

    function validSelectedNoteIndexes() {
        var indexes = [];
        var seen = {};
        for (var i = 0; i < selectedNoteItem.length; i++) {
            var idx = Number(selectedNoteItem[i]);
            if (idx >= 0 && idx < itemModel.count && !seen[idx]) {
                indexes.push(idx);
                seen[idx] = true;
            }
        }
        return indexes;
    }

    function clearRenameState() {
        forceActiveFocus();
        for (var i = 0; i < itemModel.count; i++) {
            var item = itemListView.itemAtIndex(i);
            if (item)
                item.isRename = false;
        }
    }

    function selectNoteItem(index) {
        if (index < 0 || index >= itemModel.count)
            return;

        selectedNoteItem = [index];
        selectSize = 1;
        itemListView.currentIndex = index;
        itemListView.lastCurrentIndex = index;
    }

    function onDeleteNote() {
        if (webVisible || isVoiceToText) {
            console.log("No notes available, cannot delete");
            return;
        }

        var validIndexes = validSelectedNoteIndexes();
        if (validIndexes.length === 0)
            return;
        
        messageDialogLoader.messageData = validIndexes.length;
        if (messageDialogLoader.active) {
            messageDialogLoader.item.show();
        }
        messageDialogLoader.showDialog(VNoteMessageDialogHandler.DeleteNote, ret => {
            if (!ret) {
                return;
            }
            clearRenameState();
            var delList = itemListView.sortAndDeduplicate(validSelectedNoteIndexes());
            var delIdList = [];
            var deleIndex = Number.MAX_SAFE_INTEGER;
            for (var i = 0; i < delList.length; i++) {
                var deleteItem = itemModel.get(delList[i]);
                if (!deleteItem)
                    continue;
                delIdList.push(deleteItem.noteId);
                if (delList[i] < deleIndex)
                    deleIndex = delList[i];
            }
            if (delIdList.length === 0)
                return;
            if (!VNoteMainManager.deleteNote(delIdList))
                return;
            var delIdMap = {};
            for (var k = 0; k < delIdList.length; ++k)
                delIdMap[delIdList[k]] = true;
            for (var j = itemModel.count - 1; j >= 0; --j) {
                var note = itemModel.get(j);
                if (note && delIdMap[note.noteId])
                    itemModel.remove(j);
            }
            deleteNotes(delIdList.length);
            if (itemModel.count === 0) {
                selectedNoteItem = [];
                selectSize = 0;
                emptyItemList();
            } else if (itemModel.count <= deleIndex) {
                var newIndex = itemModel.count - 1;
                selectedNoteItem = [newIndex];
                selectSize = 1;
                itemListView.currentIndex = newIndex;
                itemListView.lastCurrentIndex = newIndex;
                noteItemChanged(itemModel.get(newIndex).noteId);
            } else {
                selectedNoteItem = [deleIndex];
                selectSize = 1;
                itemListView.currentIndex = deleIndex;
                itemListView.lastCurrentIndex = deleIndex;
                noteItemChanged(itemModel.get(deleIndex).noteId);
            }
            gc();
            deleteFinished();
        });
    }

    function refreshMoveFolderModel() {
        moveFolderModel.clear();
        if (!sourceFolderModel)
            return;

        for (var i = 0; i < sourceFolderModel.count; i++) {
            if (i === currentFolderIndex)
                continue;

            var folder = sourceFolderModel.get(i);
            moveFolderModel.append({
                name: folder.name,
                icon: folder.icon,
                folderId: folder.folderId
            });
        }
    }

    function onMoveNote() {
        if (webVisible || isVoiceToText) {
            console.log("No notes available, cannot move");
            return;
        }

        var validIndexes = validSelectedNoteIndexes();
        if (validIndexes.length === 0)
            return;

        refreshMoveFolderModel();
        if (moveFolderModel.count === 0) {
            console.log("No other notebook available to move to");
            return;
        }
        clearRenameState();
        
        var desText = "";
        if (validIndexes.length > 1) {
            desText = qsTr("move ") + validIndexes.length + qsTr(" notes to :");
        } else {
            var index = itemListView.contextIndex >= 0 && itemListView.contextIndex < itemModel.count ? itemListView.contextIndex : validIndexes[0];
            desText = qsTr("move ") + itemModel.get(index).name + qsTr(" note to :");
        }
        dialogWindow.name = desText;
        dialogWindow.show();
    }

    function onSaveAudio() {
        if (webVisible) {
            console.log("No notes available, cannot save audio");
            return;
        }
        if (validSelectedNoteIndexes().length === 0)
            return;
        
        folderDialogLoader.saveType = VNoteMainManager.Voice;
        if (!folderDialogLoader.active) {
            folderDialogLoader.active = true;
        } else {
            folderDialogLoader.item.open();
        }
    }

    function onSaveNote() {
        if (webVisible) {
            console.log("No notes available, cannot save note");
            return;
        }

        var validIndexes = validSelectedNoteIndexes();
        if (validIndexes.length === 0)
            return;
        
        if (validIndexes.length > 1) {
            folderDialogLoader.saveType = VNoteMainManager.Text;
            if (!folderDialogLoader.active) {
                folderDialogLoader.active = true;
            } else {
                folderDialogLoader.item.open();
            }
        } else {
            fileDialogLoader.saveType = VNoteMainManager.Text;
            fileDialogLoader.active = false;
            fileDialogLoader.active = true;
        }
    }

    function renameCurrentItem() {
        var validIndexes = validSelectedNoteIndexes();
        if (validIndexes.length !== 1)
            return;
        var item = itemListView.itemAtIndex(validIndexes[0]);
        if (!item)
            return;
        item.isRename = true;
    }

    function cancelRename() {
        for (var i = 0; i < itemListView.count; i++) {
            var item = itemListView.itemAtIndex(i);
            if (item && item.isRename) {
                item.isRename = false;
            }
        }
    }

    function showContextMenuOnCurrentItem() {
        // 在当前选中项位置弹出笔记右键菜单
        if (selectedNoteItem.length === 0)
            return;
        // 保持与右键逻辑一致：刷新 contextIndex、检查语音可用性和文本内容
        var validIndexes = validSelectedNoteIndexes();
        if (validIndexes.length === 0)
            return;
        itemListView.contextIndex = validIndexes[0];
        var list = [];
        for (var i = 0; i < validIndexes.length; i++) {
            list.push(itemModel.get(validIndexes[i]).noteId);
        }
        VNoteMainManager.checkNoteVoice(list);
        VNoteMainManager.checkNoteText(list);
        var item = itemListView.itemAtIndex(itemListView.contextIndex);
        if (!item)
            return;
        try {
            noteCtxMenu.popup(item, item.width / 2, item.height);
        } catch (e) {
            noteCtxMenu.popup();
        }
    }

    height: 480
    visible: true
    width: 640

    Keys.onPressed: function(event) {
        switch (event.key) {
         case Qt.Key_Up:
             if (itemListView.count > 0) {
                 if (itemListView.currentIndex <= 0) {
                     itemListView.currentIndex = itemListView.count - 1;
                 } else {
                     itemListView.currentIndex--;
                 }
                 selectedNoteItem = [itemListView.currentIndex];
                 selectSize = 1;
                 noteItemChanged(itemModel.get(itemListView.currentIndex).noteId);
             }
             event.accepted = true;
             break;
         case Qt.Key_Down:
             if (itemListView.count > 0) {
                 if (itemListView.currentIndex >= itemListView.count - 1) {
                     itemListView.currentIndex = 0;
                 } else {
                     itemListView.currentIndex++;
                 }
                 selectedNoteItem = [itemListView.currentIndex];
                 selectSize = 1;
                 noteItemChanged(itemModel.get(itemListView.currentIndex).noteId);
             }
             event.accepted = true;
             break;
        case Qt.Key_Delete:
            if (rootItem.isDragging || webVisible || isRecordingAudio || isPlay || isVoiceToText) {
                console.log("No notes available, cannot delete");
                return;
            }
            rootItem.onDeleteNote();
            event.accepted = true;
            break;
        default:
            break;
        }
    }
    onSelectSizeChanged: {
        var validIndexes = validSelectedNoteIndexes();
        if (selectSize !== validIndexes.length) {
            selectedNoteItem = validIndexes;
            selectSize = validIndexes.length;
            return;
        }

        mulChoices(validIndexes.length);
        if (validIndexes.length > 1) {
            var list = [];
            for (var i = 0; i < validIndexes.length; i++) {
                list.push(itemModel.get(validIndexes[i]).noteId);
            }
            VNoteMainManager.checkNoteVoice(list);
            VNoteMainManager.checkNoteText(list);
        }
    }

    ListModel {
        id: itemModel

    }

    ListModel {
        id: moveFolderModel

    }

    MoveDialog {
        id: dialogWindow

        folderModel: moveFolderModel

        onMoveToFolder: {
            if (isVoiceToText) {
                console.log("Cannot move note while voice to text is in progress");
                return;
            }
            var indexList = [];
            var validIndexes = validSelectedNoteIndexes();
            for (var i = 0; i < validIndexes.length; i++) {
                var moveItem = itemModel.get(validIndexes[i]);
                if (moveItem)
                    indexList.push(moveItem.noteId);
            }
            if (indexList.length === 0)
                return;
            var folderId = moveFolderModel.get(index).folderId;
            VNoteMainManager.moveNotesToFolderId(indexList, folderId);
        }
    }

    VNoteMessageDialogLoader {
        id: messageDialogLoader

    }

    DragControl {
        id: dragControl

    }

    Loader {
        id: fileDialogLoader

        property var saveType: VNoteMainManager.Note

        active: false
        asynchronous: true

        sourceComponent: FileDialog {
            id: fileDialog

            title: qsTr("Save As")
            fileMode: FileDialog.SaveFile
            nameFilters: saveFilters[saveType]

            property url initialFolder: {
                var savedPath = "";
                if (saveType === VNoteMainManager.Text || saveType === VNoteMainManager.Html) {
                    savedPath = VNoteMainManager.getSavedTextPath();
                } else if (saveType === VNoteMainManager.Voice) {
                    savedPath = VNoteMainManager.getSavedVoicePath();
                }
                
                if (savedPath && savedPath.length > 0) {
                    return "file://" + savedPath;
                } else {
                    return StandardPaths.standardLocations(StandardPaths.DesktopLocation)[0];
                }
            }
            
            Component.onCompleted: {
                // Set folder property for Qt5 compatibility
                try {
                    fileDialog.folder = initialFolder;
                } catch (e) {
                    console.log("folder property not available, trying currentFolder");
                }
                
                // Set currentFolder property for Qt6 compatibility
                try {
                    fileDialog.currentFolder = initialFolder;
                } catch (e) {
                    console.log("currentFolder property not available, using folder");
                }
                
                var defaultFileName = "";
                var validIndexes = validSelectedNoteIndexes();
                if (validIndexes.length > 0 && itemModel.get(validIndexes[0])) {
                    // 在搜索模式下使用纯文本标题，避免HTML标签出现在文件名中
                    if (isSearch) {
                        defaultFileName = VNoteMainManager.getNotePlainTitle(itemModel.get(validIndexes[0]).noteId);
                    } else {
                        defaultFileName = itemModel.get(validIndexes[0]).name;
                    }
                    if (saveType === VNoteMainManager.Text && !defaultFileName.toLowerCase().endsWith('.txt')) {
                        defaultFileName += '.txt';
                    } else if (saveType === VNoteMainManager.Html && !defaultFileName.toLowerCase().endsWith('.html')) {
                        defaultFileName += '.html';
                    }
                }
                
                try {
                    if (defaultFileName) {
                        fileDialog.currentFile = Qt.resolvedUrl(initialFolder + "/" + defaultFileName);
                    } else {
                        fileDialog.currentFile = "";
                    }
                } catch (e) {
                    console.log("currentFile property not available");
                }
                
                fileDialog.open();
            }
            onAccepted: {
                var idList = [];
                var validIndexes = validSelectedNoteIndexes();
                for (var i = 0; i < validIndexes.length; i++) {
                    idList.push(itemModel.get(validIndexes[i]).noteId);
                }
                
                var selectedFileUrl;
                
                if (typeof fileDialog.selectedFile !== 'undefined' && fileDialog.selectedFile) {
                    selectedFileUrl = fileDialog.selectedFile;
                } 
                else if (typeof fileDialog.fileUrl !== 'undefined' && fileDialog.fileUrl) {
                    selectedFileUrl = fileDialog.fileUrl;
                }
                else if (typeof fileDialog.currentFile !== 'undefined' && fileDialog.currentFile) {
                    selectedFileUrl = fileDialog.currentFile;
                }
                
                if (!selectedFileUrl || selectedFileUrl.toString().length === 0) {
                    return;
                }

                var fileUrl = selectedFileUrl.toString();
                var folderPath = "";
                if (typeof fileDialog.folder !== 'undefined' && fileDialog.folder) {
                    folderPath = fileDialog.folder.toString();
                } else if (typeof fileDialog.currentFolder !== 'undefined' && fileDialog.currentFolder) {
                    folderPath = fileDialog.currentFolder.toString();
                }
                
                if (!folderPath) {
                    if (fileUrl.startsWith("file://")) {
                        fileUrl = fileUrl.substring(7);
                    }
                    folderPath = fileUrl.substring(0, fileUrl.lastIndexOf('/'));
                } else {
                    if (folderPath.startsWith("file://")) {
                        folderPath = folderPath.substring(7);
                    }
                }
                
                VNoteMainManager.saveUserSelectedPath(folderPath, saveType);

                VNoteMainManager.saveAs(idList, selectedFileUrl, saveType);
            }
        }
    }

    Loader {
        id: folderDialogLoader

        property var saveType: VNoteMainManager.Note

        active: false
        asynchronous: true

        sourceComponent: FolderDialog {
            id: folderDialog

            title: qsTr("Save As")
            
            property url initialFolder: {
                var savedPath = "";
                if (saveType === VNoteMainManager.Text || saveType === VNoteMainManager.Html) {
                    savedPath = VNoteMainManager.getSavedTextPath();
                } else if (saveType === VNoteMainManager.Voice) {
                    savedPath = VNoteMainManager.getSavedVoicePath();
                }
                
                if (savedPath && savedPath.length > 0) {
                    return "file://" + savedPath;
                } else {
                    return StandardPaths.standardLocations(StandardPaths.DesktopLocation)[0];
                }
            }

            Component.onCompleted: {
                // Set folder property for Qt5 compatibility
                try {
                    folderDialog.folder = initialFolder;
                } catch (e) {
                    console.log("folder property not available for FolderDialog, trying currentFolder");
                }
                
                // Set currentFolder property for Qt6 compatibility
                try {
                    folderDialog.currentFolder = initialFolder;
                } catch (e) {
                    console.log("currentFolder property not available for FolderDialog, using folder");
                }
                
                folderDialog.open();
            }
            onAccepted: {
                var list = [];
                var validIndexes = validSelectedNoteIndexes();
                for (var i = 0; i < validIndexes.length; i++) {
                    list.push(itemModel.get(validIndexes[i]).noteId);
                }
                
                var selectedFolderUrl;
                
                if (typeof folderDialog.selectedFolder !== 'undefined' && folderDialog.selectedFolder) {
                    selectedFolderUrl = folderDialog.selectedFolder;
                }
                else if (typeof folderDialog.currentFolder !== 'undefined' && folderDialog.currentFolder) {
                    selectedFolderUrl = folderDialog.currentFolder;
                }
                else if (typeof folderDialog.folder !== 'undefined' && folderDialog.folder) {
                    selectedFolderUrl = folderDialog.folder;
                }
                
                if (!selectedFolderUrl || selectedFolderUrl.toString().length === 0) {
                    return;
                }
                
                var folderPath = selectedFolderUrl.toString();
                if (folderPath.startsWith("file://")) {
                    folderPath = folderPath.substring(7);
                }
                VNoteMainManager.saveUserSelectedPath(folderPath, saveType);
                
                VNoteMainManager.saveAs(list, selectedFolderUrl, saveType);
            }
        }
    }

    Loader {
        id: noSearchResultsLoader

        active: false
        asynchronous: true

        sourceComponent: Rectangle {
            id: noSearchResultsRect

            color: "transparent"
            height: itemListView.height
            visible: false
            width: itemListView.width

            Component.onCompleted: {
                noSearchResultsRect.visible = true;
                itemListView.visible = false;
            }

            Label {
                anchors.centerIn: parent
                color: DTK.themeType === ApplicationHelper.LightType ? "#66000000" : "#66ffffff"
                font: DTK.fontManager.t6
                text: qsTr("No search results")
            }
        }
    }

    VNoteRightMenu {
        id: noteCtxMenu

        menuType: ActionManager.NoteCtxMenu

        onAboutToShow: {
            var contextValid = itemListView.contextIndex >= 0 && itemListView.contextIndex < itemModel.count;
            if (contextValid) {
                var setTop = true;
                if (itemModel.get(itemListView.contextIndex).isTop === "top") {
                    setTop = false;
                }
                var topItem = ActionManager.getActionById(ActionManager.NoteTop);
                topItem.text = setTop ? qsTr("Sticky on Top") : qsTr("Unpin");
            }

            ActionManager.enableVoicePlayActions(!isPlay && !isRecordingAudio);
            // 录音、播放或语音转文字中禁用删除
            ActionManager.enableAction(ActionManager.NoteDelete, !isRecordingAudio && !isPlay && !isVoiceToText);
            
            // 在搜索状态下禁用移动、置顶和新建笔记选项
            if (isSearching) {
                ActionManager.enableAction(ActionManager.NoteMove, false);
                ActionManager.enableAction(ActionManager.NoteTop, false);
                ActionManager.enableAction(ActionManager.NoteAddNew, false);
            } else {
                // 录音、播放或语音转文字时禁用移动和新建（会影响当前笔记），但置顶保持可用
                ActionManager.enableAction(ActionManager.NoteMove, !isRecordingAudio && !isPlay && !isVoiceToText);
                ActionManager.enableAction(ActionManager.NoteTop, contextValid);  // 置顶是轻量操作，当前项有效时可用
                ActionManager.enableAction(ActionManager.NoteAddNew, !isRecordingAudio && !isPlay && !isVoiceToText);
            }
            
            // 录音时保存语音菜单置灰，但重命名、置顶和保存笔记保持可用
            if (isRecordingAudio) {
                ActionManager.enableAction(ActionManager.NoteSaveVoice, false);
            }
        }
        onActionTrigger: actionId => {
            // 检查是否有笔记内容，如果处于初始界面则不执行操作
            if (webVisible) {
                console.log("No notes available, cannot perform menu action:", actionId);
                return;
            }
            
            switch (actionId) {
            case ActionManager.NoteRename:
                if (itemListView.contextIndex < 0 || itemListView.contextIndex >= itemModel.count)
                    return;
                var currentItem = itemListView.itemAtIndex(itemListView.contextIndex);
                if (currentItem) {
                    currentItem.isRename = true;
                }
                break;
            case ActionManager.NoteTop:
                if (itemListView.contextIndex < 0 || itemListView.contextIndex >= itemModel.count)
                    return;
                var setTop = true;
                if (itemModel.get(itemListView.contextIndex).isTop === "top") {
                    setTop = false;
                }
                VNoteMainManager.updateTop(itemModel.get(itemListView.contextIndex).noteId, setTop);
                break;
            case ActionManager.NoteMove:
                onMoveNote();
                break;
            case ActionManager.NoteDelete:
                rootItem.onDeleteNote();
                break;
            case ActionManager.SaveNoteAsText:
                rootItem.onSaveNote();
                break;
            case ActionManager.SaveNoteAsHtml:
                onTriggered: {
                    var validIndexes = validSelectedNoteIndexes();
                    if (validIndexes.length === 0)
                        return;

                    if (validIndexes.length > 1) {
                        folderDialogLoader.saveType = VNoteMainManager.Html;
                        if (!folderDialogLoader.active) {
                            folderDialogLoader.active = true;
                        } else {
                            folderDialogLoader.item.open();
                        }
                    } else {
                        fileDialogLoader.saveType = VNoteMainManager.Html;
                        fileDialogLoader.active = false;
                        fileDialogLoader.active = true;
                    }
                }
                break;
            case ActionManager.NoteSaveVoice:
                rootItem.onSaveAudio();
                break;
            case ActionManager.NoteAddNew:
                VNoteMainManager.createNote();
                break;
            default:
                break;
            }
        }
    }

    Connections {
        function handleUpdateNoteList(notesData) {
            itemModel.clear();
            for (var i = 0; i < notesData.length; i++) {
                var itemIsTop = notesData[i].isTop ? "top" : "normal";
                itemModel.append({
                    name: notesData[i].name,
                    time: notesData[i].time,
                    isTop: itemIsTop,
                    icon: notesData[i].icon,
                    folderName: notesData[i].folderName,
                    noteId: notesData[i].noteId
                });
            }
        }

        target: VNoteMainManager

        onNoSearchResult: {
            if (!noSearchResultsLoader.active) {
                noSearchResultsLoader.active = true;
            } else {
                noSearchResultsLoader.item.visible = true;
                itemListView.visible = false;
            }
        }
        onSearchFinished: {
            if (noSearchResultsLoader.active && noSearchResultsLoader.item.visible) {
                noSearchResultsLoader.item.visible = false;
                itemListView.visible = true;
            }
            isSearch = true;
            handleUpdateNoteList(notesData);
            selectedNoteItem = [0];
            noteItemChanged(notesData[0].noteId);
            selectSize = 1;
        }
        onNoteTitleChanged: function(noteId, newTitle) {
            for (var i = 0; i < itemModel.count; i++) {
                if (itemModel.get(i).noteId === noteId) {
                    itemModel.set(i, { "name": newTitle });
                    console.log("Updated note title in list without reload, noteId:", noteId);
                    break;
                }
            }
        }
    }

    ListView {
        id: itemListView

        property var contextIndex: -1
        property var lastCurrentIndex: 0

        function sortAndDeduplicate(arr) {
            // Convert to integers and remove duplicates using a Set
            var uniqueInts = [...new Set(arr)].map(Number);

            // Sort the array in descending order
            uniqueInts.sort(function (a, b) {
                return b - a;
            });
            return uniqueInts;
        }

        anchors.fill: parent
        boundsBehavior: Flickable.StopAtBounds
        clip: true
        model: itemModel
        spacing: itemSpacing
        visible: true

        ScrollBar.vertical: ScrollBar {
            id: verticalScrollBar

            parent: rootItem.scrollBarParent ? rootItem.scrollBarParent : itemListView
            x: rootItem.scrollBarParent ? rootItem.scrollBarRightAnchor - width : parent.width - width
            y: 0
            height: parent.height
        }

        delegate: Rectangle {
            id: rootItemDelegate

            property bool hovered: false
            property bool isRename: false
            property bool isSelected: selectedNoteItem.indexOf(index) !== -1
            property var startMove: [-1, -1]

            color: isSelected ? (rootItem.activeFocus ? palette.highlight : (DTK.themeType === ApplicationHelper.LightType ? "#33000000" : "#33FFFFFF")) : (DTK.themeType === ApplicationHelper.LightType ? "white" : "#0CFFFFFF")
            enabled: !isPlay || itemListView.currentIndex === index
            // 录音时：当前项保持正常显示，其他项置灰
            opacity: (isRecordingAudio && index !== itemListView.currentIndex) ? 0.5 : 1.0
            // 列表项高度始终使用非重命名的计算方式，重命名时高度保持不变
            height: (function() {
                var topM = 8;
                var bottomM = 8;
                var gap = 1; 
                var titleH = Math.ceil(noteNameLabel.implicitHeight);
                var timeH = Math.ceil(timeLabel.implicitHeight);
                var searchRowH = isSearch ? Math.max(16, Math.ceil(folderNameLabel.implicitHeight)) : 0;
                var gapCount = isSearch ? 2 : 1; 
                var content = topM + titleH + gap * gapCount + timeH + (isSearch ? searchRowH : 0) + bottomM;
                var baseMin = isSearch ? 67 : 50;
                return Math.max(baseMin, content);
            })()
            radius: 6
            width: itemListView.width

            // 与 DccItemBackground 一致：卡片底部 1px 淡阴影
            BoxShadow {
                anchors.fill: parent
                cornerRadius: rootItemDelegate.radius
                hollow: true
                shadowBlur: 0
                shadowColor: DTK.themeType === ApplicationHelper.LightType ? Qt.rgba(0, 0, 0, 0.05)
                                                                           : Qt.rgba(0, 0, 0, 0.3)
                shadowOffsetX: 0
                shadowOffsetY: 1
                spread: 0
                visible: !rootItemDelegate.isSelected
                z: -1
            }

            Keys.onPressed: function(event) {
                if (isRename) {
                    if (event.key === Qt.Key_Escape) {
                        renameLine.text = model.name;
                        isRename = false;
                        rootItem.forceActiveFocus();
                    } else if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
                        isRename = false;
                        rootItem.forceActiveFocus();
                    }
                } else {
                    if (event.key === Qt.key_delete) {
                        if (webVisible) {
                            console.log("No notes available, cannot delete");
                            return;
                        }
                        rootItem.onDeleteNote();
                    }
                }
            }
            onIsRenameChanged: {
                renameLine.forceActiveFocus();
            }

            ColumnLayout {
                id: itemLayout

                anchors.bottomMargin: 8
                anchors.fill: parent
                anchors.leftMargin: 10
                anchors.rightMargin: 10
                anchors.topMargin: 8
                spacing: isRename ? 7 : 1

                Label {
                    id: noteNameLabel

                    // width: parent.width - 10
                    Layout.fillWidth: true
                    color: DTK.themeType === ApplicationHelper.LightType ? (isSelected ? (rootItem.activeFocus ? palette.highlightedText : "black") : "black") : "white"
                    elide: Text.ElideRight
                    font: DTK.fontManager.t6
                    height: implicitHeight
                    horizontalAlignment: Text.AlignHLeft
                    text: model.name
                    visible: !isRename
                }

                Label {
                    id: timeLabel

                    Layout.fillWidth: true
                    color: isSelected ? (rootItem.activeFocus ? "#7FFFFFFF" : DTK.themeType === ApplicationHelper.LightType ? "#7F000000" : "#7FFFFFFF") : (DTK.themeType === ApplicationHelper.LightType ? "#7F000000" : "#7FFFFFFF")
                    font.pixelSize: 10
                    height: implicitHeight
                    horizontalAlignment: Text.AlignHLeft
                    text: model.time
                    visible: !isRename
                }

                ToolTip {
                    id: itemNameTip

                    text: model.name
                    visible: rootItemDelegate.hovered
                }

                LineEdit {
                    id: renameLine

                    Layout.fillHeight: false
                    Layout.fillWidth: true
                    Layout.minimumWidth: 100  
                    Layout.maximumWidth: itemListView.width - 12  
                    Layout.leftMargin: 6 - 10  // = -4
                    Layout.rightMargin: 6 - 10 // = -4
                    Layout.topMargin: isSearch ? 6 : (10 - 8)  
                    Layout.bottomMargin: isSearch ? 0 : (10 - 8)  
                    font: DTK.fontManager.t6
                    leftPadding: 6
                    rightPadding: 30 
                    topPadding: 4
                    bottomPadding: 4
                    implicitHeight: Math.max(30, Math.ceil(font.pixelSize * 1.6))
                    maximumLength: 64
                    Layout.preferredHeight: (function() {
                        var itemH = rootItemDelegate.height;
                        var outerTop = 8, outerBottom = 8;
                        if (isSearch) {
                            // 搜索模式：需要为下方的文件夹行预留空间
                            var topM = 6 - 8;  // 搜索时上边距
                            var afterGap = 7;  // 与下方间距
                            var searchRowH = Math.max(16, Math.ceil(folderNameLabel.implicitHeight));
                            var available = itemH - (outerTop + outerBottom + topM + afterGap + searchRowH);
                            return Math.min(implicitHeight, Math.max(30, available));
                        } else {
                            // 非搜索模式：在固定列表项高度内适应，考虑上下边距
                            var topM = 10 - 8;     // 非搜索时上边距
                            var bottomM = 10 - 8;  // 非搜索时下边距
                            var available = itemH - (outerTop + outerBottom + topM + bottomM);
                            return Math.min(implicitHeight, Math.max(30, available));
                        }
                    })()
                    text: model.name
                    visible: rootItemDelegate.isRename

                    backgroundColor: Palette {
                        normal: Qt.rgba(1, 1, 1, 0.85)
                        normalDark: Qt.rgba(0, 0, 0, 0.5)
                    }

                    onActiveFocusChanged: {
                        noteItemMouseArea.enabled = false;
                        if (activeFocus) {
                            if (isSearch) {
                                text = VNoteMainManager.getNotePlainTitle(model.noteId);
                            }
                            selectAll();
                        } else {
                            var originalTitle = isSearch ? VNoteMainManager.getNotePlainTitle(model.noteId) : model.name;
                            if (text.length !== 0 && text !== originalTitle) {
                                VNoteMainManager.renameNote(model.noteId, text);
                            } else {
                                renameLine.text = originalTitle;
                            }
                            noteItemMouseArea.enabled = true;
                            rootItemDelegate.isRename = false;
                        }
                    }
                }

                RowLayout {
                    id: rowlayout

                    Layout.fillHeight: true
                    Layout.fillWidth: true
                    visible: isSearch

                    Rectangle {
                        height: 16
                        radius: 8
                        width: 16

                        Image {
                            id: _image

                            antialiasing: true
                            fillMode: Image.PreserveAspectCrop
                            height: 16
                            smooth: true
                            source: "image://Provider/" + model.icon
                            visible: false
                            width: 16
                        }

                        Rectangle {
                            //矩形
                            id: _mask

                            antialiasing: true
                            color: "red"
                            height: 16
                            radius: 8
                            smooth: true
                            visible: false  //不可见
                            width: 16
                        }

                        OpacityMask {
                            id: mask_image

                            anchors.fill: _image
                            antialiasing: true
                            maskSource: _mask    //用作遮罩的项目
                            source: _image
                            visible: true
                        }
                    }

                    Label {
                        id: folderNameLabel

                        Layout.fillHeight: true
                        Layout.fillWidth: true
                        color: isSelected ? (rootItem.activeFocus ? "#7FFFFFFF" : DTK.themeType === ApplicationHelper.LightType ? "#7F000000" : "#7FFFFFFF") : (DTK.themeType === ApplicationHelper.LightType ? "#7F000000" : "#7FFFFFFF")
                        font.pixelSize: 10
                        horizontalAlignment: Text.AlignLeft
                        text: model.folderName
                    }
                }
            }

            MouseArea {
                id: noteItemMouseArea

                property bool held: false

                onHeldChanged: rootItem.isDragging = held

                acceptedButtons: Qt.LeftButton | Qt.RightButton
                anchors.fill: parent
                drag.target: this
                hoverEnabled: true

                onClicked: {
                    if (mouse.button === Qt.RightButton) {
                        // 录音时只允许当前选中笔记的右键菜单
                        if (isRecordingAudio && selectedNoteItem.indexOf(index) === -1) {
                            console.log("Cannot show context menu for non-selected note while recording audio");
                            return;
                        }
                        
                        var selectedIndexes = validSelectedNoteIndexes();
                        if (selectedIndexes.length > 1) {
                            ActionManager.visibleMulChoicesActions(false);
                        } else {
                            if (itemListView.itemAtIndex(itemListView.lastCurrentIndex))
                                itemListView.itemAtIndex(itemListView.lastCurrentIndex).isRename = false;
                            selectedNoteItem = [index];
                            selectSize = 1;
                            itemListView.currentIndex = index;
                            itemListView.lastCurrentIndex = index;
                            itemListView.contextIndex = index;
                            ActionManager.visibleMulChoicesActions(true);
                        }
                        var list = [];
                        var validIndexes = validSelectedNoteIndexes();
                        for (var i = 0; i < validIndexes.length; i++) {
                            list.push(itemModel.get(validIndexes[i]).noteId);
                        }
                        VNoteMainManager.checkNoteVoice(list);
                        VNoteMainManager.checkNoteText(list);
                        noteCtxMenu.popup();
                    } else {
                        // 录音时禁用笔记切换
                        if (isRecordingAudio) {
                            console.log("Cannot switch note while recording audio");
                            return;
                        }
                        
                        if (itemListView.currentIndex === index && selectedNoteItem.length === 1) {
                            var curDelegate = itemListView.itemAtIndex(index);
                            if (curDelegate && curDelegate.isSelected) {
                                console.warn("ListView.onClicked: early return");
                                return;
                            }
                        }
                        switch (mouse.modifiers) {
                        case Qt.ControlModifier:
                            var nextSelection = selectedNoteItem.slice();
                            var pos = nextSelection.indexOf(index);
                            if (pos != -1) {
                                nextSelection.splice(pos, 1);
                                selectSize--;
                            } else {
                                nextSelection.push(index);
                                selectSize++;
                            }
                            selectedNoteItem = nextSelection;
                            break;
                        case Qt.ShiftModifier:
                            var anchorIndex = Math.max(0, Math.min(itemListView.lastCurrentIndex, itemModel.count - 1));
                            var targetIndex = Math.max(0, Math.min(index, itemModel.count - 1));
                            var startIndex = Math.min(targetIndex, anchorIndex);
                            var endIndex = Math.max(targetIndex, anchorIndex);
                            var rangeSelection = [];
                            for (var i = startIndex; i <= endIndex; i++)
                                rangeSelection.push(i);
                            selectedNoteItem = rangeSelection;
                            itemListView.lastCurrentIndex = anchorIndex;
                            selectSize = rangeSelection.length;
                            break;
                        default:
                            if (itemListView.itemAtIndex(itemListView.lastCurrentIndex))
                                itemListView.itemAtIndex(itemListView.lastCurrentIndex).isRename = false;
                            selectedNoteItem = [index];
                            selectSize = 1;
                            itemListView.currentIndex = index;
                            itemListView.lastCurrentIndex = index;
                            noteItemChanged(Number(itemModel.get(index).noteId));

                            break;
                        }
                    }
                }
                onDoubleClicked: {
                    // 录音时允许双击重命名
                    var renameItem = itemListView.itemAtIndex(index);
                    if (renameItem)
                        renameItem.isRename = true;
                }
                onEntered: {
                    if (noteNameLabel.implicitWidth > noteNameLabel.width)
                        rootItemDelegate.hovered = true;
                }
                onExited: {
                    rootItemDelegate.hovered = false;
                }
                onPositionChanged: function(mouse) {
                    // 录音或播放时不启动拖拽，避免后续 dropRelease 链路
                    if (isRecordingAudio || isPlay) {
                        held = false;
                        dragControl.visible = false;
                        return;
                    }
                    if (!held) {
                        if ((startMove[0] !== -1 || startMove[1] !== -1) && ((Math.abs(mouse.x - startMove[0]) > 5) || (Math.abs(mouse.y - startMove[1]) > 5))) {
                            held = true;
                        } else {
                            return;
                        }
                    }
                    var validIndexes = validSelectedNoteIndexes();
                    if (validIndexes.length > 0 && itemModel.get(validIndexes[0])) {
                        var globPos = mapToGlobal(mouse.x, mouse.y);
                        dragControl.itemNumber = validIndexes.length;
                        dragControl.itemText = itemModel.get(validIndexes[0]).name;
                        dragControl.visible = true;
                        dragControl.x = globPos.x;
                        dragControl.y = globPos.y;
                        mouseChanged(globPos.x, globPos.y);
                    } else {
                        dragControl.visible = false;
                    }
                }
                onPressed: function(mouse) {
                    startMove[0] = mouse.x;
                    startMove[1] = mouse.y;
                }
                onReleased: function(mouse) {
                    if (isRecordingAudio || isPlay) {
                        startMove = [-1, -1];
                        held = false;
                        dragControl.visible = false;
                        return;
                    }
                    startMove = [-1, -1];
                    if (held && dragControl.visible && mouse.button === Qt.LeftButton) {
                        dropRelease();
                    }
                    held = false;
                    dragControl.visible = false;
                }
            }
        }
        footer: Component {
            id: footerComponent

            Rectangle {
                color: "transparent"
                height: 10
                width: itemListView.width
            }
        }

        MouseArea {
            anchors.fill: parent
            propagateComposedEvents: true

            onPressed: {
                var index = itemListView.currentIndex;
                var item = itemListView.itemAtIndex(index);
                if (item.isRename) {
                    var clickX = mouse.x;
                    var clickY = mouse.y;
                    var localPoint = item.mapFromItem(parent, clickX, clickY);
                    if (!item.contains(localPoint)) {
                        rootItem.forceActiveFocus();
                    }
                } else {
                    rootItem.forceActiveFocus();
                }
                mouse.accepted = false;
            }
        }

        section {
            criteria: ViewSection.FullString
            property: "isTop"

            delegate: Rectangle {
                color: "transparent"
                height: section == "top" ? Math.max(18, Math.ceil(sectionStickyFontMetrics.height) + 6) : 16
                width: parent.width

                FontMetrics {
                    id: sectionStickyFontMetrics
                    font.pixelSize: 12
                }

                RowLayout {
                    anchors.left: parent.left
                    anchors.verticalCenter: parent.verticalCenter
                    spacing: 4
                    visible: section == "top" && !isSearch
                    
                    // 置顶图标
                    Image {
                        id: sectionPinIcon
                        
                        Layout.preferredWidth: 12
                        Layout.preferredHeight: 12
                        source: "qrc:/dsg/icons/pin_top.dci"
                        fillMode: Image.PreserveAspectFit
                        smooth: true
                        antialiasing: true
                    }
                    
                    Text {
                        color: "#b3000000"
                        font.pixelSize: 12
                        verticalAlignment: Text.AlignVCenter
                        text: qsTr("Sticky Notes")
                    }
                }

                Rectangle {
                    anchors.centerIn: parent
                    color: "#0D000000"
                    height: 1
                    visible: section != "top" && VNoteMainManager.getTop() && !isSearch
                    width: parent.width
                }
            }
        }
    }
}
