import QtQuick
import Quickshell
import qs.Common
import qs.Services
import qs.Widgets

Rectangle {
    id: root
    readonly property var log: Log.scoped("CalendarOverviewCard")

    LayoutMirroring.enabled: I18n.isRtl
    LayoutMirroring.childrenInherit: true

    implicitWidth: SettingsData.showWeekNumber ? 736 : 700

    property bool showEventDetails: false
    property date selectedDate: systemClock.date
    property var selectedDateEvents: []
    property bool hasEvents: selectedDateEvents && selectedDateEvents.length > 0
    property var detailEvent: null
    property bool showEditor: false
    property var editorEvent: null

    signal closeDash
    signal navFocusRequested

    function weekStartQt() {
        if (SettingsData.firstDayOfWeek >= 7 || SettingsData.firstDayOfWeek < 0) {
            return Qt.locale().firstDayOfWeek;
        }
        return SettingsData.firstDayOfWeek;
    }

    function weekStartJs() {
        return weekStartQt() % 7;
    }

    function startOfWeek(dateObj) {
        const d = new Date(dateObj);
        const jsDow = d.getDay();
        const diff = (jsDow - weekStartJs() + 7) % 7;
        d.setDate(d.getDate() - diff);
        return d;
    }

    function endOfWeek(dateObj) {
        const d = new Date(dateObj);
        const jsDow = d.getDay();
        const add = (weekStartJs() + 6 - jsDow + 7) % 7;
        d.setDate(d.getDate() + add);
        return d;
    }

    function getWeekNumber(dateObj) {
        // Set time to noon to avoid potential Daylight Saving Time related bugs
        const weekStartDay = startOfWeek(dateObj);
        weekStartDay.setHours(12, 0, 0, 0);

        let week1Start;

        if (weekStartJs() === 1) {
            // ISO 8601 Standard, week start on Monday
            // A week belongs to the year its Thursday falls in
            // So we have to get the yearTarget from weekStartDay instead of dateObj
            let yearTarget = weekStartDay;
            yearTarget.setDate(yearTarget.getDate() + 3); // Monday + 3 = Thursday

            // Week 1 is the week containing Jan 4th
            const jan4 = new Date(yearTarget.getFullYear(), 0, 4);
            week1Start = startOfWeek(jan4);
        } else {
            // Traditional / US Standard, week start on Sunday
            // A week belongs to the year its Sunday falls in
            let yearTarget = weekStartDay;
            yearTarget.setDate(yearTarget.getDate() + 6); // Monday + 6 = Sunday

            // Week 1 is the week containing Jan 1st
            const jan1 = new Date(yearTarget.getFullYear(), 0, 1);
            week1Start = startOfWeek(jan1);
        }

        week1Start.setHours(12, 0, 0, 0);

        const diffDays = Math.round((weekStartDay.getTime() - week1Start.getTime()) / 86400000); // Number of miliseconds in a day
        return Math.floor(diffDays / 7) + 1;
    }

    function updateSelectedDateEvents() {
        const events = (CalendarService && CalendarService.calendarAvailable) ? CalendarService.getEventsForDate(selectedDate) : [];
        if (JSON.stringify(events) === JSON.stringify(selectedDateEvents))
            return;
        selectedDateEvents = events;
    }

    function loadEventsForMonth() {
        if (!CalendarService || !CalendarService.calendarAvailable) {
            return;
        }

        const firstOfMonth = new Date(calendarGrid.displayDate.getFullYear(), calendarGrid.displayDate.getMonth(), 1);
        const lastOfMonth = new Date(calendarGrid.displayDate.getFullYear(), calendarGrid.displayDate.getMonth() + 1, 0);

        const startDate = startOfWeek(firstOfMonth);
        startDate.setDate(startDate.getDate() - 7);

        const endDate = endOfWeek(lastOfMonth);
        endDate.setDate(endDate.getDate() + 7);

        CalendarService.loadEvents(startDate, endDate);
    }

    function goToToday() {
        const now = systemClock.date;
        calendarGrid.selectedDate = now;
        calendarGrid.displayDate = now;
        root.selectedDate = now;
        loadEventsForMonth();
    }

    function moveSelection(days) {
        let d = new Date(calendarGrid.selectedDate);
        d.setDate(d.getDate() + days);
        calendarGrid.selectedDate = d;
        root.selectedDate = d;
        if (d.getMonth() !== calendarGrid.displayDate.getMonth() || d.getFullYear() !== calendarGrid.displayDate.getFullYear()) {
            calendarGrid.displayDate = d;
            loadEventsForMonth();
        }
    }

    function shiftMonth(delta) {
        let d = new Date(calendarGrid.displayDate);
        d.setMonth(d.getMonth() + delta);
        calendarGrid.displayDate = d;
        loadEventsForMonth();
    }

    function handleKeyEvent(event) {
        if (showEventDetails) {
            if (event.key === Qt.Key_Escape) {
                showEventDetails = false;
                return true;
            }
            return false;
        }
        switch (event.key) {
        case Qt.Key_Left:
        case Qt.Key_H:
            moveSelection(I18n.isRtl ? 1 : -1);
            return true;
        case Qt.Key_Right:
        case Qt.Key_L:
            moveSelection(I18n.isRtl ? -1 : 1);
            return true;
        case Qt.Key_Up:
        case Qt.Key_K:
            moveSelection(-7);
            return true;
        case Qt.Key_Down:
        case Qt.Key_J:
            moveSelection(7);
            return true;
        case Qt.Key_PageUp:
            shiftMonth(-1);
            return true;
        case Qt.Key_PageDown:
            shiftMonth(1);
            return true;
        case Qt.Key_T:
            goToToday();
            return true;
        case Qt.Key_Return:
        case Qt.Key_Enter:
        case Qt.Key_Space:
            root.selectedDate = calendarGrid.selectedDate;
            showEventDetails = true;
            return true;
        }
        return false;
    }

    onSelectedDateChanged: updateSelectedDateEvents()

    onShowEventDetailsChanged: {
        if (showEventDetails) {
            taskInput.forceActiveFocus();
        } else {
            navFocusRequested();
        }
    }

    Component.onCompleted: {
        loadEventsForMonth();
        updateSelectedDateEvents();
    }

    Connections {
        function onEventsByDateChanged() {
            updateSelectedDateEvents();
        }

        function onCalendarAvailableChanged() {
            if (CalendarService && CalendarService.calendarAvailable) {
                loadEventsForMonth();
            }
            updateSelectedDateEvents();
        }

        target: CalendarService
        enabled: CalendarService !== null
    }

    radius: Theme.cornerRadius
    color: Theme.nestedSurface
    border.color: Theme.outlineMedium
    border.width: 1

    Column {
        anchors.fill: parent
        anchors.margins: Theme.spacingM
        spacing: Theme.spacingS

        Rectangle {
            id: dankWarning
            width: parent.width
            readonly property bool showWarning: CalendarService?.dankNeedsLaunch ?? false
            visible: showWarning
            height: showWarning ? Math.max(28, warningRow.implicitHeight) + Theme.spacingS : 0
            radius: Theme.cornerRadius
            color: Theme.warningHover
            border.color: Theme.withAlpha(Theme.warning, 0.35)
            border.width: 1

            Row {
                id: warningRow
                anchors.left: parent.left
                anchors.right: parent.right
                anchors.verticalCenter: parent.verticalCenter
                anchors.leftMargin: Theme.spacingS
                anchors.rightMargin: Theme.spacingS
                spacing: Theme.spacingS

                DankIcon {
                    name: "warning"
                    size: 16
                    color: Theme.warning
                    anchors.verticalCenter: parent.verticalCenter
                }

                StyledText {
                    width: parent.width - 16 - Theme.spacingS - (launchButton.visible ? launchButton.width + Theme.spacingS : 0)
                    anchors.verticalCenter: parent.verticalCenter
                    text: (CalendarService && CalendarService.dankBinaryExists) ? I18n.tr("DankCalendar isn't running") : I18n.tr("DankCalendar isn't installed")
                    font.pixelSize: Theme.fontSizeSmall
                    color: Theme.surfaceText
                    horizontalAlignment: Text.AlignLeft
                    wrapMode: Text.Wrap
                }

                DankButton {
                    id: launchButton
                    anchors.verticalCenter: parent.verticalCenter
                    visible: CalendarService && CalendarService.dankBinaryExists
                    text: I18n.tr("Launch")
                    buttonHeight: 26
                    backgroundColor: Theme.primary
                    textColor: Theme.primaryText
                    onClicked: CalendarService.launchDankCalendar()
                }
            }
        }

        Item {
            width: parent.width
            height: 40
            visible: showEventDetails

            DankActionButton {
                buttonSize: 32
                iconSize: 14
                iconName: "arrow_back"
                iconColor: Theme.primary
                anchors.verticalCenter: parent.verticalCenter
                anchors.left: parent.left
                anchors.leftMargin: Theme.spacingS
                onClicked: root.showEventDetails = false
            }

            DankActionButton {
                buttonSize: 32
                iconSize: 16
                iconName: "event"
                iconColor: Theme.primary
                anchors.verticalCenter: parent.verticalCenter
                anchors.right: parent.right
                anchors.rightMargin: Theme.spacingS
                visible: CalendarService && CalendarService.canCreateEvents
                onClicked: {
                    root.editorEvent = null;
                    root.showEditor = true;
                }
            }

            StyledText {
                anchors.left: parent.left
                anchors.right: parent.right
                anchors.leftMargin: 32 + Theme.spacingS * 2
                anchors.rightMargin: (CalendarService && CalendarService.canCreateEvents) ? 32 + Theme.spacingS * 2 : Theme.spacingS
                height: 40
                anchors.verticalCenter: parent.verticalCenter
                text: {
                    const dateStr = Qt.formatDate(selectedDate, "MMM d");
                    if (selectedDateEvents && selectedDateEvents.length > 0) {
                        const eventCount = selectedDateEvents.length === 1 ? I18n.tr("1 task", "task count next to a date") : I18n.tr("%1 tasks", "task count next to a date, %1 is the number of tasks").arg(selectedDateEvents.length);
                        return dateStr + " • " + eventCount;
                    }
                    return dateStr;
                }
                font.pixelSize: Theme.fontSizeMedium
                color: Theme.surfaceText
                font.weight: Font.Medium
                verticalAlignment: Text.AlignVCenter
                elide: Text.ElideRight
            }
        }

        Row {
            width: parent.width
            height: 28
            visible: !showEventDetails

            DankActionButton {
                buttonSize: 28
                iconSize: 14
                iconName: "chevron_left"
                iconColor: Theme.primary
                onClicked: root.shiftMonth(-1)
            }

            StyledText {
                width: parent.width - 84
                height: 28
                text: calendarGrid.displayDate.toLocaleDateString(I18n.locale(), "MMMM yyyy")
                font.pixelSize: Theme.fontSizeMedium
                color: Theme.surfaceText
                font.weight: Font.Medium
                horizontalAlignment: Text.AlignHCenter
                verticalAlignment: Text.AlignVCenter
            }

            DankActionButton {
                buttonSize: 28
                iconSize: 14
                iconName: "today"
                iconColor: Theme.primary
                onClicked: root.goToToday()
            }

            DankActionButton {
                buttonSize: 28
                iconSize: 14
                iconName: "chevron_right"
                iconColor: Theme.primary
                onClicked: root.shiftMonth(1)
            }
        }

        Row {
            width: parent.width
            height: parent.height - 28 - Theme.spacingS
            visible: !showEventDetails
            spacing: SettingsData.showWeekNumber ? Theme.spacingS : 0

            Column {
                id: weekNumberColumn
                visible: SettingsData.showWeekNumber
                width: SettingsData.showWeekNumber ? 28 : 0
                height: parent.height
                spacing: Theme.spacingS

                Item {
                    width: parent.width
                    height: 18
                }

                Grid {
                    width: parent.width
                    height: parent.height - 18 - Theme.spacingS
                    columns: 1
                    rows: 6

                    Repeater {
                        model: 6
                        Rectangle {
                            width: parent.width
                            height: parent.height / 6
                            color: "transparent"

                            StyledText {
                                anchors.centerIn: parent
                                text: {
                                    const rowDate = new Date(calendarGrid.firstDay);
                                    rowDate.setDate(rowDate.getDate() + index * 7);
                                    return root.getWeekNumber(rowDate);
                                }
                                font.pixelSize: Theme.fontSizeSmall
                                color: Theme.surfaceTextSecondary
                                font.weight: Font.Medium
                            }
                        }
                    }
                }
            }

            Column {
                width: SettingsData.showWeekNumber ? (parent.width - weekNumberColumn.width - parent.spacing) : parent.width
                height: parent.height
                spacing: Theme.spacingS

                Row {
                    width: parent.width
                    height: 18

                    Repeater {
                        model: {
                            const days = [];
                            const qtFirst = weekStartQt();
                            for (let i = 0; i < 7; ++i) {
                                const qtDay = ((qtFirst - 1 + i) % 7) + 1;
                                days.push(I18n.locale().dayName(qtDay, Locale.ShortFormat));
                            }
                            return days;
                        }

                        Rectangle {
                            width: parent.width / 7
                            height: 18
                            color: "transparent"

                            StyledText {
                                anchors.centerIn: parent
                                text: modelData
                                font.pixelSize: Theme.fontSizeSmall
                                color: Theme.surfaceTextSecondary
                                font.weight: Font.Medium
                            }
                        }
                    }
                }

                Grid {
                    id: calendarGrid
                    width: parent.width
                    height: parent.height - 18 - Theme.spacingS
                    columns: 7
                    rows: 6

                    property date displayDate: systemClock.date
                    property date selectedDate: systemClock.date

                    readonly property date firstDay: {
                        const firstOfMonth = new Date(displayDate.getFullYear(), displayDate.getMonth(), 1);
                        return startOfWeek(firstOfMonth);
                    }

                    Repeater {
                        model: 42

                        Rectangle {
                            readonly property date dayDate: {
                                const date = new Date(parent.firstDay);
                                date.setDate(date.getDate() + index);
                                return date;
                            }
                            readonly property bool isCurrentMonth: dayDate.getMonth() === calendarGrid.displayDate.getMonth()
                            readonly property bool isToday: dayDate.toDateString() === new Date().toDateString()
                            readonly property bool isSelected: dayDate.toDateString() === calendarGrid.selectedDate.toDateString()

                            width: parent.width / 7
                            height: parent.height / 6
                            color: "transparent"

                            Rectangle {
                                anchors.centerIn: parent
                                width: Math.min(parent.width - 4, parent.height - 4, 32)
                                height: width
                                color: isToday ? Theme.primaryHover : dayArea.containsMouse ? Theme.primaryHoverLight : Theme.withAlpha(Theme.primaryHoverLight, 0)
                                radius: Theme.cornerRadius
                                border.color: (isSelected && !isToday) ? Theme.primary : Theme.withAlpha(Theme.primary, 0)
                                border.width: (isSelected && !isToday) ? 1 : 0

                                StyledText {
                                    anchors.centerIn: parent
                                    text: dayDate.getDate()
                                    font.pixelSize: Theme.fontSizeSmall
                                    color: isToday ? Theme.primary : isCurrentMonth ? Theme.surfaceText : Theme.surfaceVariantText
                                    font.weight: isToday ? Font.Medium : Font.Normal
                                }

                                Row {
                                    anchors.bottom: parent.bottom
                                    anchors.horizontalCenter: parent.horizontalCenter
                                    anchors.bottomMargin: 3
                                    spacing: Theme.spacingXXS
                                    visible: CalendarService && CalendarService.calendarAvailable && CalendarService.hasEventsForDate(dayDate)

                                    Repeater {
                                        model: {
                                            const evs = CalendarService.getEventsForDate(dayDate);
                                            const seen = [];
                                            for (let i = 0; i < evs.length && seen.length < 3; i++) {
                                                const c = (evs[i].color && evs[i].color.length) ? evs[i].color : "primary";
                                                if (seen.indexOf(c) === -1)
                                                    seen.push(c);
                                            }
                                            return seen;
                                        }

                                        Rectangle {
                                            width: 5
                                            height: 5
                                            radius: 2.5
                                            color: modelData === "primary" ? (isToday ? Qt.lighter(Theme.primary, 1.3) : Theme.primary) : modelData
                                            opacity: isToday ? 0.95 : 0.8
                                        }
                                    }
                                }
                            }

                            MouseArea {
                                id: dayArea
                                anchors.fill: parent
                                hoverEnabled: true
                                cursorShape: Qt.PointingHandCursor
                                onClicked: {
                                    calendarGrid.selectedDate = dayDate;
                                    root.selectedDate = dayDate;
                                    root.showEventDetails = true;
                                }
                            }
                        }
                    }
                }
            }
        }

        Flickable {
            id: flickableArea
            width: parent.width - Theme.spacingS * 2
            height: parent.height - (showEventDetails ? 40 + 42 : 28 + 18) - Theme.spacingS
            anchors.horizontalCenter: parent.horizontalCenter
            visible: showEventDetails
            clip: true
            contentWidth: width
            contentHeight: listViewContainer.height
            interactive: listViewContainer.draggedItem === null

            Item {
                id: listViewContainer
                width: parent.width
                height: 100

                property var draggedItem: null
                property bool orderChanged: false

                function resetAndLayout() {
                    for (let i = 0; i < repeater.count; i++) {
                        let item = repeater.itemAt(i);
                        if (item) {
                            item.visualIndex = i;
                            item.isDragging = false;
                            item.isEditing = false;
                        }
                    }
                    updateLayout();
                }

                function updateLayout() {
                    let items = [];
                    for (let i = 0; i < repeater.count; i++) {
                        let item = repeater.itemAt(i);
                        if (item) {
                            items.push(item);
                        }
                    }
                    items.sort((a, b) => a.visualIndex - b.visualIndex);

                    let currentY = 0;
                    for (let i = 0; i < items.length; i++) {
                        let item = items[i];
                        if (item && !item.isDragging) {
                            item.y = currentY;
                        }
                        if (item) {
                            currentY += item.height + Theme.spacingXS;
                        }
                    }
                    listViewContainer.height = Math.max(0, currentY - Theme.spacingXS);
                }

                function checkAndReorder(dragged) {
                    let items = [];
                    for (let i = 0; i < repeater.count; i++) {
                        let item = repeater.itemAt(i);
                        if (item) {
                            items.push(item);
                        }
                    }
                    items.sort((a, b) => a.visualIndex - b.visualIndex);

                    let swapped = false;

                    // Helper to get target Y position without animation offsets
                    function getTargetY(index) {
                        let y = 0;
                        for (let i = 0; i < index; i++) {
                            y += items[i].height + Theme.spacingXS;
                        }
                        return y;
                    }

                    while (true) {
                        let draggedIdx = items.indexOf(dragged);
                        if (draggedIdx === -1)
                            break;

                        let didSwap = false;

                        // Check item above
                        if (draggedIdx > 0) {
                            let above = items[draggedIdx - 1];
                            let targetYAbove = getTargetY(draggedIdx - 1);
                            if (above && dragged.y < (targetYAbove + above.height / 2)) {
                                // Swap visualIndex
                                let temp = dragged.visualIndex;
                                dragged.visualIndex = above.visualIndex;
                                above.visualIndex = temp;

                                // Swap in local array
                                items[draggedIdx] = above;
                                items[draggedIdx - 1] = dragged;

                                listViewContainer.orderChanged = true;
                                swapped = true;
                                didSwap = true;
                            }
                        }

                        // Check item below
                        if (!didSwap && draggedIdx < items.length - 1) {
                            let below = items[draggedIdx + 1];
                            let targetYBelow = getTargetY(draggedIdx + 1);
                            if (below && (dragged.y + dragged.height) > (targetYBelow + below.height / 2)) {
                                // Swap visualIndex
                                let temp = dragged.visualIndex;
                                dragged.visualIndex = below.visualIndex;
                                below.visualIndex = temp;

                                // Swap in local array
                                items[draggedIdx] = below;
                                items[draggedIdx + 1] = dragged;

                                listViewContainer.orderChanged = true;
                                swapped = true;
                                didSwap = true;
                            }
                        }

                        if (!didSwap) {
                            break;
                        }
                    }

                    if (swapped) {
                        updateLayout();
                    }
                }

                function saveNewOrder() {
                    if (!orderChanged)
                        return;

                    let items = [];
                    for (let i = 0; i < repeater.count; i++) {
                        let item = repeater.itemAt(i);
                        if (item) {
                            items.push(item);
                        }
                    }
                    items.sort((a, b) => a.visualIndex - b.visualIndex);

                    let orderedIds = [];
                    for (let i = 0; i < items.length; i++) {
                        let tid = items[i].taskId;
                        if (tid && tid.startsWith("task_")) {
                            orderedIds.push(tid.replace("task_", ""));
                        }
                    }
                    if (orderedIds.length > 0) {
                        CalendarService.reorderTasksForDate(root.selectedDate, orderedIds);
                    }
                    orderChanged = false;
                }

                Repeater {
                    id: repeater
                    model: selectedDateEvents

                    onModelChanged: {
                        Qt.callLater(listViewContainer.resetAndLayout);
                    }

                    delegate: Rectangle {
                        id: taskItem
                        width: parent ? parent.width : 0
                        height: isEditing ? 34 : (eventContent.implicitHeight + Theme.spacingS)
                        radius: Theme.cornerRadius

                        property int modelIndex: index
                        property int visualIndex: index
                        property string taskId: (modelData && modelData.id) ? modelData.id : ""
                        property bool isDragging: false
                        property bool isEditing: false
                        property real dragMouseOffsetY: 0

                        onModelIndexChanged: {
                            visualIndex = modelIndex;
                        }

                        onYChanged: {
                            if (isDragging) {
                                listViewContainer.checkAndReorder(taskItem);
                            }
                        }

                        readonly property bool isLocalTask: taskId.startsWith("task_")
                        readonly property bool isDankTask: taskId.startsWith("vtodo_")
                        readonly property bool isTask: isLocalTask || isDankTask
                        readonly property bool canModify: isLocalTask || (isDankTask && modelData && !modelData.readOnly)
                        readonly property string quickUrl: {
                            if (isTask || !modelData)
                                return "";
                            if (modelData.meetingUrl)
                                return modelData.meetingUrl;
                            const loc = (modelData.location || "").trim();
                            if (/^https?:\/\/\S+$/i.test(loc))
                                return loc;
                            if (/^www\.\S+$/i.test(loc))
                                return "https://" + loc;
                            return modelData.url || "";
                        }
                        readonly property string quickUrlLabel: {
                            const u = quickUrl.replace(/^https?:\/\//i, "");
                            if (u.length <= 40)
                                return u;
                            return u.slice(0, 39) + "…";
                        }
                        readonly property color baseAccent: {
                            if (isLocalTask || !modelData || !modelData.color || !modelData.color.length)
                                return Theme.primary;
                            return modelData.color;
                        }
                        readonly property color accentColor: (isTask && modelData && modelData.completed) ? Theme.withAlpha(baseAccent, 0.4) : baseAccent
                        readonly property color surfaceColor: isDragging ? Theme.primaryPressed : (eventMouseArea.containsMouse ? Theme.primaryBackground : Theme.nestedSurface)

                        color: surfaceColor
                        border.color: isDragging ? Theme.primary : (eventMouseArea.containsMouse ? Theme.primaryPressed : Theme.outlineMedium)
                        border.width: (isDragging || eventMouseArea.containsMouse) ? 1 : Theme.layerOutlineWidth

                        scale: isDragging ? 1.02 : 1.0
                        z: isDragging ? 100 : visualIndex

                        Behavior on scale {
                            NumberAnimation {
                                duration: 100
                            }
                        }

                        Behavior on y {
                            id: yBehavior
                            enabled: !taskItem.isDragging
                            NumberAnimation {
                                duration: 150
                                easing.type: Easing.OutQuad
                            }
                        }

                        Component.onCompleted: {
                            visualIndex = index;
                            listViewContainer.updateLayout();
                        }

                        onHeightChanged: {
                            listViewContainer.updateLayout();
                        }

                        onIsEditingChanged: {
                            if (isEditing) {
                                editInput.forceActiveFocus();
                                editInput.selectAll();
                            }
                        }

                        Item {
                            id: accentClip
                            width: 4
                            clip: true
                            anchors.top: parent.top
                            anchors.bottom: parent.bottom
                            anchors.left: parent.left

                            Rectangle {
                                width: taskItem.width
                                height: taskItem.height
                                radius: taskItem.radius
                                color: taskItem.accentColor
                                anchors.top: parent.top
                                anchors.left: parent.left
                            }
                        }

                        // Drag Handle
                        Rectangle {
                            id: dragHandle
                            width: 24
                            height: 24
                            anchors.left: parent.left
                            anchors.leftMargin: 8
                            anchors.verticalCenter: parent.verticalCenter
                            radius: Theme.cornerRadius
                            color: "transparent"
                            visible: taskItem.isLocalTask && !taskItem.isEditing

                            DankIcon {
                                anchors.centerIn: parent
                                name: "drag_indicator"
                                size: 14
                                color: dragMouseArea.containsMouse ? Theme.primary : Theme.surfaceTextMedium
                            }

                            MouseArea {
                                id: dragMouseArea
                                anchors.fill: parent
                                hoverEnabled: true
                                cursorShape: Qt.SizeAllCursor
                                preventStealing: true

                                drag.target: taskItem
                                drag.axis: Drag.YAxis
                                drag.minimumY: 0
                                drag.maximumY: listViewContainer.height - taskItem.height

                                onPressed: {
                                    taskItem.isDragging = true;
                                    listViewContainer.orderChanged = false;
                                    listViewContainer.draggedItem = taskItem;
                                }

                                onPositionChanged: {
                                    // Handled natively by MouseArea.drag
                                }

                                onReleased: {
                                    taskItem.isDragging = false;
                                    listViewContainer.draggedItem = null;
                                    if (listViewContainer.orderChanged) {
                                        listViewContainer.saveNewOrder();
                                    } else {
                                        listViewContainer.updateLayout();
                                    }
                                }

                                onCanceled: {
                                    taskItem.isDragging = false;
                                    listViewContainer.draggedItem = null;
                                    listViewContainer.resetAndLayout();
                                }
                            }
                        }

                        Column {
                            id: eventContent

                            anchors.left: parent.left
                            anchors.right: parent.right
                            anchors.verticalCenter: parent.verticalCenter
                            anchors.leftMargin: taskItem.isLocalTask ? 60 : taskItem.isDankTask ? 36 : (Theme.spacingS + 6)
                            anchors.rightMargin: taskItem.canModify ? 64 : (taskItem.quickUrl !== "" ? 32 + Theme.spacingS : Theme.spacingXS)
                            spacing: Theme.spacingXXS
                            visible: !taskItem.isEditing

                            StyledText {
                                width: parent.width
                                text: modelData ? modelData.title : ""
                                font.pixelSize: Theme.fontSizeSmall
                                color: (taskItem.isTask && modelData && modelData.completed) ? Theme.surfaceTextSecondary : Theme.surfaceText
                                font.weight: Font.Medium
                                horizontalAlignment: Text.AlignLeft
                                elide: Text.ElideRight
                                maximumLineCount: 1
                            }

                            StyledText {
                                width: parent.width
                                text: {
                                    if (!modelData)
                                        return "";
                                    const cal = (modelData.calendar && modelData.calendar.length) ? " · " + modelData.calendar : "";
                                    if (modelData.allDay)
                                        return I18n.tr("All day", "calendar task with no specific time") + cal;
                                    if (modelData.start && modelData.end) {
                                        const timeFormat = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP";
                                        const startTime = Qt.formatTime(modelData.start, timeFormat);
                                        if (modelData.start.toDateString() !== modelData.end.toDateString() || modelData.start.getTime() !== modelData.end.getTime())
                                            return startTime + " – " + Qt.formatTime(modelData.end, timeFormat) + cal;
                                        return startTime + cal;
                                    }
                                    return "";
                                }
                                font.pixelSize: Theme.fontSizeSmall
                                color: Theme.surfaceTextMedium
                                font.weight: Font.Normal
                                horizontalAlignment: Text.AlignLeft
                                visible: text !== "" && !taskItem.isLocalTask
                            }
                        }

                        // Inline Edit Input Box
                        Rectangle {
                            id: editInputContainer
                            anchors.left: parent.left
                            anchors.right: parent.right
                            anchors.leftMargin: 36
                            anchors.rightMargin: 64
                            anchors.verticalCenter: parent.verticalCenter
                            height: 28
                            visible: taskItem.isEditing
                            color: "transparent"

                            TextInput {
                                id: editInput
                                anchors.fill: parent
                                verticalAlignment: TextInput.AlignVCenter
                                color: Theme.surfaceText
                                font.pixelSize: Theme.fontSizeSmall
                                selectByMouse: true
                                clip: true

                                text: modelData ? modelData.title : ""

                                onAccepted: {
                                    let txt = text.trim();
                                    if (txt !== "" && modelData && modelData.id) {
                                        CalendarService.editTask(modelData.id, txt);
                                    }
                                    taskItem.isEditing = false;
                                }

                                Keys.onEscapePressed: event => {
                                    taskItem.isEditing = false;
                                    event.accepted = true;
                                }
                            }
                        }

                        // Main body MouseArea (declared before the delete/edit buttons so they sit on top)
                        MouseArea {
                            id: eventMouseArea

                            anchors.fill: parent
                            anchors.leftMargin: taskItem.isLocalTask ? 32 : 6
                            anchors.rightMargin: taskItem.canModify ? 64 : 0
                            hoverEnabled: true
                            cursorShape: modelData ? Qt.PointingHandCursor : Qt.ArrowCursor
                            enabled: modelData && !taskItem.isEditing
                            onClicked: {
                                if (!modelData)
                                    return;
                                if (taskItem.isTask && taskItem.canModify) {
                                    CalendarService.toggleTask(modelData.id);
                                    return;
                                }
                                root.detailEvent = modelData;
                            }
                        }

                        DankActionButton {
                            buttonSize: 24
                            iconSize: 14
                            iconName: (modelData && modelData.meetingUrl) ? "videocam" : "link"
                            iconColor: Theme.primary
                            anchors.right: parent.right
                            anchors.rightMargin: Theme.spacingS
                            anchors.verticalCenter: parent.verticalCenter
                            visible: taskItem.quickUrl !== ""
                            tooltipText: taskItem.quickUrlLabel
                            tooltipSide: "left"
                            onClicked: Qt.openUrlExternally(taskItem.quickUrl)
                        }

                        DankActionButton {
                            buttonSize: 24
                            iconSize: 16
                            iconName: (modelData && modelData.completed) ? "check_box" : "check_box_outline_blank"
                            iconColor: (modelData && modelData.completed) ? Theme.primary : Theme.surfaceText
                            anchors.left: parent.left
                            anchors.leftMargin: taskItem.isLocalTask ? (taskItem.isEditing ? 8 : 32) : 8
                            anchors.verticalCenter: parent.verticalCenter
                            visible: taskItem.isTask
                            enabled: taskItem.canModify && !taskItem.isEditing
                            onClicked: CalendarService.toggleTask(modelData.id)
                        }

                        DankActionButton {
                            id: deleteButton
                            buttonSize: 24
                            iconSize: 14
                            iconName: taskItem.isEditing ? "close" : "delete"
                            iconColor: taskItem.isEditing ? Theme.surfaceText : Theme.error
                            anchors.right: parent.right
                            anchors.rightMargin: Theme.spacingS
                            anchors.verticalCenter: parent.verticalCenter
                            visible: taskItem.canModify
                            onClicked: {
                                if (taskItem.isEditing) {
                                    taskItem.isEditing = false;
                                    return;
                                }
                                if (modelData && modelData.id)
                                    CalendarService.removeTask(modelData.id);
                            }
                        }

                        DankActionButton {
                            buttonSize: 24
                            iconSize: 14
                            iconName: taskItem.isEditing ? "check" : "edit"
                            iconColor: taskItem.isEditing ? Theme.primary : Theme.surfaceText
                            anchors.right: deleteButton.left
                            anchors.rightMargin: Theme.spacingXS
                            anchors.verticalCenter: parent.verticalCenter
                            visible: taskItem.canModify
                            onClicked: {
                                if (!taskItem.isEditing) {
                                    taskItem.isEditing = true;
                                    return;
                                }
                                let txt = editInput.text.trim();
                                if (txt !== "" && modelData && modelData.id)
                                    CalendarService.editTask(modelData.id, txt);
                                taskItem.isEditing = false;
                            }
                        }
                    }
                }
            }
        }

        Rectangle {
            width: parent.width - Theme.spacingS * 2
            height: 34
            anchors.horizontalCenter: parent.horizontalCenter
            radius: Theme.cornerRadius
            color: Theme.nestedSurface
            border.color: Theme.outlineMedium
            border.width: 1
            visible: showEventDetails

            TextInput {
                id: taskInput
                anchors.fill: parent
                anchors.leftMargin: Theme.spacingS
                anchors.rightMargin: Theme.spacingS
                verticalAlignment: TextInput.AlignVCenter
                color: Theme.surfaceText
                font.pixelSize: Theme.fontSizeSmall
                selectByMouse: true
                clip: true

                Text {
                    text: I18n.tr("Add a task...", "placeholder in the new-task input field")
                    color: Theme.outlineButton
                    visible: taskInput.text.length === 0
                    font.pixelSize: Theme.fontSizeSmall
                    anchors.verticalCenter: parent.verticalCenter
                }

                onAccepted: {
                    let txt = text.trim();
                    if (txt !== "") {
                        CalendarService.addTaskForDate(root.selectedDate, txt);
                        text = "";
                    }
                }

                Keys.onEscapePressed: event => {
                    root.showEventDetails = false;
                    event.accepted = true;
                }
            }
        }
    }

    Loader {
        anchors.fill: parent
        z: 1000
        active: root.detailEvent !== null

        sourceComponent: CalendarEventDetail {
            eventData: root.detailEvent
            canEdit: CalendarService && CalendarService.canCreateEvents && root.detailEvent && !root.detailEvent.readOnly && !(root.detailEvent.id && root.detailEvent.id.startsWith("task_"))
            onCloseRequested: root.detailEvent = null
            onEditRequested: {
                root.editorEvent = root.detailEvent;
                root.detailEvent = null;
                root.showEditor = true;
            }
            onDeleteRequested: {
                if (root.detailEvent && root.detailEvent.id)
                    CalendarService.deleteEvent(root.detailEvent.id, null);
                root.detailEvent = null;
            }
        }
    }

    Loader {
        anchors.fill: parent
        z: 1000
        active: root.showEditor

        sourceComponent: CalendarEventEditor {
            eventData: root.editorEvent
            initialDate: root.selectedDate
            onCloseRequested: {
                root.showEditor = false;
                root.editorEvent = null;
            }
            onSaved: {
                root.showEditor = false;
                root.editorEvent = null;
            }
        }
    }

    SystemClock {
        id: systemClock
        precision: SystemClock.Hours
    }

    Connections {
        target: SessionService

        function onSessionResumed() {
            systemClock.enabled = false;
            systemClock.enabled = true;
        }
    }
}
