// Selection mode: a GNOME-style rubber band over the frozen screen.
//
// Behaviours copied from GNOME 42: the overlay opens with a sensible centred
// selection already in place (so the shutter is immediately useful), dragging
// inside moves it, dragging a corner resizes from the opposite corner, and
// dragging anywhere else starts a fresh band.
//
// A single MouseArea owns all of it. Nested MouseAreas for the handles would
// fight the move/create area for the press, and the hit priorities are much
// easier to reason about in one place.

import QtQuick
import qs.config

Item {
    id: root

    // Anything smaller than this on release is treated as a stray click and the
    // previous selection is restored.
    readonly property real minSize: 12
    // Pointer distance from a corner that counts as grabbing its handle.
    readonly property real handleGrab: 24
    readonly property real handleSize: 14

    property real selX: 0
    property real selY: 0
    property real selW: 0
    property real selH: 0

    readonly property bool hasSelection: root.selW >= root.minSize && root.selH >= root.minSize
    readonly property rect selection: Qt.rect(root.selX, root.selY, root.selW, root.selH)

    // Double-clicking inside the band captures, like confirming a crop.
    signal committed

    // "none" | "new" | "move" | "nw" | "ne" | "sw" | "se"
    property string _grab: "none"
    property real _anchorX: 0
    property real _anchorY: 0
    property real _pressX: 0
    property real _pressY: 0
    property real _origX: 0
    property real _origY: 0
    property rect _prev: Qt.rect(0, 0, 0, 0)

    onWidthChanged: root._resetIfEmpty()
    onHeightChanged: root._resetIfEmpty()
    Component.onCompleted: root._resetIfEmpty()

    function _resetIfEmpty(): void {
        if (root.selW === 0 && root.selH === 0)
            root.resetSelection();
    }

    // Centred, roughly the middle half of the screen.
    function resetSelection(): void {
        if (root.width <= 0 || root.height <= 0)
            return;
        root.selW = Math.round(root.width * 0.55);
        root.selH = Math.round(root.height * 0.55);
        root.selX = Math.round((root.width - root.selW) / 2);
        root.selY = Math.round((root.height - root.selH) / 2);
    }

    function _clampX(v: real): real {
        return Math.max(0, Math.min(root.width, v));
    }
    function _clampY(v: real): real {
        return Math.max(0, Math.min(root.height, v));
    }

    function _near(a: real, b: real): bool {
        return Math.abs(a - b) <= root.handleGrab;
    }

    function _hitTest(px: real, py: real): string {
        const x2 = root.selX + root.selW;
        const y2 = root.selY + root.selH;
        if (root.hasSelection) {
            if (root._near(px, root.selX) && root._near(py, root.selY))
                return "nw";
            if (root._near(px, x2) && root._near(py, root.selY))
                return "ne";
            if (root._near(px, root.selX) && root._near(py, y2))
                return "sw";
            if (root._near(px, x2) && root._near(py, y2))
                return "se";
            if (px > root.selX && px < x2 && py > root.selY && py < y2)
                return "move";
        }
        return "new";
    }

    function _cursorFor(m: string): int {
        switch (m) {
        case "nw":
        case "se":
            return Qt.SizeFDiagCursor;
        case "ne":
        case "sw":
            return Qt.SizeBDiagCursor;
        case "move":
            return Qt.SizeAllCursor;
        default:
            return Qt.CrossCursor;
        }
    }

    // Rebuild the band from a fixed anchor corner and the live pointer.
    function _dragTo(px: real, py: real): void {
        const cx = root._clampX(px);
        const cy = root._clampY(py);
        root.selX = Math.min(root._anchorX, cx);
        root.selY = Math.min(root._anchorY, cy);
        root.selW = Math.abs(cx - root._anchorX);
        root.selH = Math.abs(cy - root._anchorY);
    }

    Spotlight {
        anchors.fill: parent
        holeVisible: root.hasSelection
        hole: root.selection
    }

    Frame {
        x: root.selX
        y: root.selY
        width: root.selW
        height: root.selH
        visible: root.hasSelection
        strokeWidth: 2
        strokeColor: Theme.accent
    }

    // ── Corner handles ──────────────────────────────────────────────────────
    Repeater {
        model: [
            {
                gx: 0,
                gy: 0
            },
            {
                gx: 1,
                gy: 0
            },
            {
                gx: 0,
                gy: 1
            },
            {
                gx: 1,
                gy: 1
            }
        ]

        Rectangle {
            required property var modelData

            visible: root.hasSelection
            width: root.handleSize
            height: root.handleSize
            radius: width / 2
            border.width: 0
            color: Theme.accent
            x: root.selX + modelData.gx * root.selW - width / 2
            y: root.selY + modelData.gy * root.selH - height / 2

            // A dark core keeps the handle readable on top of a light photo.
            Rectangle {
                anchors.centerIn: parent
                width: parent.width - 6
                height: width
                radius: width / 2
                border.width: 0
                color: Theme.bgDark
            }
        }
    }

    // ── Live size readout ───────────────────────────────────────────────────
    Rectangle {
        id: readout
        visible: root.hasSelection
        implicitWidth: readoutText.implicitWidth + 24
        implicitHeight: 34
        radius: Theme.pillRadius
        border.width: 0
        color: Theme.alpha(Theme.bgPopover, Theme.popoverAlpha)

        x: Math.max(0, Math.min(root.width - width, root.selX + (root.selW - width) / 2))
        // Inside the band when there is room, otherwise tucked just above it.
        y: root.selH > 110 ? root.selY + (root.selH - height) / 2 : Math.max(0, root.selY - height - 10)

        Text {
            id: readoutText
            anchors.centerIn: parent
            text: Math.round(root.selW) + " × " + Math.round(root.selH)
            color: Theme.fg
            // Tabular figures so the readout doesn't twitch while dragging.
            font.family: Theme.fontFamily
            font.features: Theme.tabularFigures
            font.pixelSize: Theme.fontSize
        }
    }

    MouseArea {
        id: area
        anchors.fill: parent
        hoverEnabled: true
        cursorShape: root._cursorFor(root._grab !== "none" ? root._grab : root._hitTest(area.mouseX, area.mouseY))

        onPressed: event => {
            root._prev = root.selection;
            root._grab = root._hitTest(event.x, event.y);
            root._pressX = event.x;
            root._pressY = event.y;
            root._origX = root.selX;
            root._origY = root.selY;

            const x2 = root.selX + root.selW;
            const y2 = root.selY + root.selH;
            switch (root._grab) {
            case "nw":
                root._anchorX = x2;
                root._anchorY = y2;
                break;
            case "ne":
                root._anchorX = root.selX;
                root._anchorY = y2;
                break;
            case "sw":
                root._anchorX = x2;
                root._anchorY = root.selY;
                break;
            case "se":
                root._anchorX = root.selX;
                root._anchorY = root.selY;
                break;
            case "new":
                root._anchorX = root._clampX(event.x);
                root._anchorY = root._clampY(event.y);
                root.selX = root._anchorX;
                root.selY = root._anchorY;
                root.selW = 0;
                root.selH = 0;
                break;
            }
        }

        onPositionChanged: event => {
            if (root._grab === "none")
                return;
            if (root._grab === "move") {
                root.selX = Math.max(0, Math.min(root.width - root.selW, root._origX + (event.x - root._pressX)));
                root.selY = Math.max(0, Math.min(root.height - root.selH, root._origY + (event.y - root._pressY)));
            } else {
                root._dragTo(event.x, event.y);
            }
        }

        onReleased: {
            // A plain click outside the band would otherwise wipe the selection
            // down to nothing; treat it as "no change" instead.
            if (root._grab !== "move" && !root.hasSelection) {
                root.selX = root._prev.x;
                root.selY = root._prev.y;
                root.selW = root._prev.width;
                root.selH = root._prev.height;
            }
            root._grab = "none";
        }

        onDoubleClicked: event => {
            if (root.hasSelection && event.x > root.selX && event.x < root.selX + root.selW && event.y > root.selY && event.y < root.selY + root.selH)
                root.committed();
        }
    }
}
