// The GNOME 42 screenshot UI.
//
// Print freezes the screen, this overlay paints that frozen frame full-bleed
// and puts the picker on top of it. Because the frame is a still, nothing under
// the overlay animates while the user aims, and the overlay can never end up in
// its own screenshot.
//
// The grab happens in services/Capture.qml *before* ShellState flips to
// "capture", so by the time this window maps the backdrop is already on disk.

import Quickshell
import Quickshell.Wayland
import QtQuick
import qs.config
import qs.services

PanelWindow {
    id: win

    visible: ShellState.captureOpen
    color: "transparent"

    anchors {
        top: true
        bottom: true
        left: true
        right: true
    }

    // Fullscreen overlays must not reserve space, or every window on the
    // workspace gets resized as the picker opens and closes.
    exclusiveZone: 0

    WlrLayershell.namespace: "qs-capture" // matched by a layerrule in hypr/rules.lua
    WlrLayershell.layer: WlrLayer.Overlay
    WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive

    onVisibleChanged: {
        if (!win.visible)
            return;
        // Hyprland reports window geometry in layout-global coordinates; the
        // picker works in window-local ones. On a single monitor this is 0,0.
        Capture.originX = win.screen ? win.screen.x : 0;
        Capture.originY = win.screen ? win.screen.y : 0;
        keys.forceActiveFocus();
    }

    // Fire whatever the current mode has selected.
    function capture(): void {
        if (Capture.mode === "screen") {
            Capture.commit(null);
            return;
        }
        if (Capture.mode === "window") {
            const r = picker.selectedRect;
            if (r)
                Capture.commit(r);
            return;
        }
        if (!selection.hasSelection)
            return;
        const s = selection.selection;
        Capture.commit(Qt.rect(s.x + Capture.originX, s.y + Capture.originY, s.width, s.height));
    }

    function cycleMode(step: int): void {
        const order = ["screen", "window", "selection"];
        const i = order.indexOf(Capture.mode);
        Capture.mode = order[(i + step + order.length) % order.length];
    }

    FocusScope {
        id: keys
        anchors.fill: parent
        focus: true

        Keys.onPressed: event => {
            switch (event.key) {
            case Qt.Key_Escape:
                Capture.close();
                break;
            case Qt.Key_Return:
            case Qt.Key_Enter:
            case Qt.Key_Space:
                win.capture();
                break;
            case Qt.Key_Left:
                win.cycleMode(-1);
                break;
            case Qt.Key_Right:
                win.cycleMode(1);
                break;
            case Qt.Key_1:
                Capture.mode = "screen";
                break;
            case Qt.Key_2:
                Capture.mode = "window";
                break;
            case Qt.Key_3:
                Capture.mode = "selection";
                break;
            case Qt.Key_P:
                Capture.showPointer = !Capture.showPointer;
                break;
            default:
                return;
            }
            event.accepted = true;
        }

        // Painted under the frozen frame so a failed grab (no wlr-screencopy)
        // still gives the picker something opaque to sit on.
        Rectangle {
            anchors.fill: parent
            color: Theme.bgDark
            border.width: 0
        }

        // The frozen screen. grim -o pins the grab to this output, so filling
        // the window is an exact 1:1 mapping; the source is 4500x3000 device
        // pixels drawn into 3000x2000 logical ones, i.e. full sharpness.
        Image {
            anchors.fill: parent
            source: Capture.freezeUrl
            fillMode: Image.Stretch
            // Unique filename per grab plus cache:false — otherwise QML would
            // happily repaint a previous session's frame.
            cache: false
            // Synchronous so the overlay never flashes black on the way in; a
            // raw PPM decode is a parse, not a decompress.
            asynchronous: false
            visible: status === Image.Ready
        }

        // ── Screen mode ─────────────────────────────────────────────────────
        // Nothing to pick, so just outline the output the way GNOME does.
        Frame {
            anchors.fill: parent
            visible: Capture.mode === "screen"
            strokeWidth: 3
            strokeColor: Theme.accent
        }

        // ── Window mode ─────────────────────────────────────────────────────
        WindowPicker {
            id: picker
            anchors.fill: parent
            visible: Capture.mode === "window"
            originX: Capture.originX
            originY: Capture.originY
            onPicked: win.capture()
        }

        // ── Selection mode ──────────────────────────────────────────────────
        SelectionLayer {
            id: selection
            anchors.fill: parent
            visible: Capture.mode === "selection"
            onCommitted: win.capture()
        }

        CaptureBar {
            anchors {
                horizontalCenter: parent.horizontalCenter
                bottom: parent.bottom
                bottomMargin: 56
            }
            captureEnabled: {
                if (Capture.mode === "window")
                    return picker.selectedRect !== null;
                if (Capture.mode === "selection")
                    return selection.hasSelection;
                return true;
            }
            onCaptureRequested: win.capture()
        }
    }
}
