pragma ComponentBehavior: Bound
import Quickshell
import Quickshell.Hyprland
import Quickshell.Io
import QtQuick
import QtQuick.Layouts
import QtQuick.Effects
import Quickshell.Wayland
import qs.config
import qs.modules.components

Scope {
    id: root
    property bool active: false
    property rect selectedRegion: Qt.rect(0, 0, 0, 0)
    property string tempScreenshot: ""

    IpcHandler {
        target: "screen"
        function capture() {
            if (root.active) {
                console.info("screencap", "already active");
                return;
            }
            console.info("screencap", "starting capture");
            root.active = true;
        }
    }

    LazyLoader {
        active: root.active
        component: PanelWindow {
            id: win
            property bool closing: false
            property bool ready: false
            property bool processing: false
            property bool windowMode: false
            property string savedPath: ""
            property bool savedSuccess: false

            color: Appearance.m3colors.m3surface
            anchors { top: true; left: true; right: true; bottom: true }
            WlrLayershell.layer: WlrLayer.Overlay
            WlrLayershell.exclusionMode: ExclusionMode.Ignore
            WlrLayershell.namespace: "nucleus:screencapture"

            Component.onCompleted: {
                var ts = Qt.formatDateTime(new Date(), "yyyy-MM-dd_hh-mm-ss");
                root.tempScreenshot = "/tmp/screenshot_" + ts + ".png";
            }

            function close() {
                if (closing) return;
                closing = true;
                closeAnim.start();
            }

            function saveFullscreen() {
                console.info("screencap", "saveFullscreen started");
                win.processing = true;
                screencopy.grabToImage(function(result) {
                    console.info("screencap", "fullscreen grabbed");
                    var ts = Qt.formatDateTime(new Date(), "yyyy-MM-dd_hh-mm-ss");
                    win.savedPath = Quickshell.env("HOME") + "/Pictures/Screenshots/screenshot_" + ts + ".png";

                    console.info("screencap", "saving to: " + win.savedPath);
                    if (result.saveToFile(win.savedPath)) {
                        console.info("screencap", "saved, copying");
                        Quickshell.execDetached({
                            command: ["sh", "-c", "cat '" + win.savedPath + "' | wl-copy --type image/png"]
                        });
                        win.savedSuccess = true;
                    } else {
                        console.info("screencap", "save failed");
                        win.savedSuccess = false;
                    }
                    win.processing = false;
                    console.info("screencap", "closing window");
                    win.close();
                });
            }

            Component {
                id: ffmpegProc
                Process {
                    property string outputPath
                    property bool success: false

                    onExited: (code) => {
                        console.info("screencap", "ffmpeg exited: " + code);
                        success = code === 0;

                        if (success) {
                            console.info("screencap", "copying to clipboard");
                            Quickshell.execDetached({
                                command: ["sh", "-c", "cat '" + outputPath + "' | wl-copy --type image/png"]
                            });
                        }

                        Quickshell.execDetached({ command: ["rm", root.tempScreenshot] });

                        win.savedSuccess = success;
                        win.processing = false;
                        console.info("screencap", "done, closing");
                        win.close();
                        destroy();
                    }
                }
            }

            function saveRegion(rect, suffix) {
                console.info("screencap", "saveRegion started: " + rect.x + "," + rect.y + " " + rect.width + "x" + rect.height);
                screencopy.grabToImage(function(result) {
                    console.info("screencap", "full screenshot grabbed for cropping");
                    if (!result.saveToFile(root.tempScreenshot)) {
                        console.info("screencap", "ERROR: failed to save temp screenshot");
                        win.savedSuccess = false;
                        win.processing = false;
                        win.close();
                        return;
                    }

                    console.info("screencap", "temp saved, cropping with ffmpeg");
                    var ts = Qt.formatDateTime(new Date(), "yyyy-MM-dd_hh-mm-ss");
                    win.savedPath = Quickshell.env("HOME") + "/Pictures/Screenshots/screenshot_" + ts + suffix + ".png";

                    ffmpegProc.createObject(win, {
                        command: ["ffmpeg", "-i", root.tempScreenshot, "-vf", "crop=" + Math.floor(rect.width) + ":" + Math.floor(rect.height) + ":" + Math.floor(rect.x) + ":" + Math.floor(rect.y), "-y", win.savedPath],
                        outputPath: win.savedPath,
                        running: true
                    });
                });
            }

            function captureFullscreen() {
                win.processing = true;
                saveFullscreen();
            }

            function captureWindow(rect) {
                win.processing = true;
                saveRegion(rect, "_window");
            }

            function captureRegion() {
                if (!ready || !selection.hasSelection) return;
                win.processing = true;
                saveRegion(root.selectedRegion, "_region");
            }

            ScreencopyView {
                id: screencopy
                anchors.fill: parent
                captureSource: win.screen
                z: -999
                live: false

                onHasContentChanged: {
                    console.info("screencap", "hasContent: " + hasContent);
                    if (hasContent) {
                        console.info("screencap", "grabbing for preview");
                        grabToImage(function(result) {
                            console.info("screencap", "preview grabbed: " + result.url);
                            frozen.source = result.url;
                            readyTimer.start();
                        });
                    }
                }
            }

            Timer {
                id: readyTimer
                interval: Metrics.chronoDuration("normal") + 50
                onTriggered: {
                    console.info("screencap", "UI ready");
                    win.ready = true;
                }
            }

            Item {
                anchors.fill: parent
                focus: true

                Keys.onEscapePressed: win.close()
                Keys.onPressed: event => {
                    if (event.key === Qt.Key_F) {
                        win.captureFullscreen();
                        event.accepted = true;
                    } else if (event.key === Qt.Key_W) {
                        win.windowMode = !win.windowMode;
                        event.accepted = true;
                    }
                }

                Image {
                    id: bg
                    anchors.fill: parent
                    source: Config.runtime.appearance.background.path
                    fillMode: Image.PreserveAspectCrop
                    opacity: 0
                    scale: 1

                    layer.enabled: true
                    layer.effect: MultiEffect {
                        blurEnabled: true
                        blur: 1.0
                        blurMax: 64
                        brightness: -0.1
                    }

                    onStatusChanged: {
                        if (status === Image.Ready) fadeIn.start();
                    }

                    NumberAnimation on opacity {
                        id: fadeIn
                        to: 1
                        duration: Metrics.chronoDuration("normal")
                        easing.type: Appearance.animation.easing
                    }
                }

                Item {
                    id: container
                    anchors.centerIn: parent
                    width: win.width
                    height: win.height

                    layer.enabled: true
                    layer.effect: MultiEffect {
                        shadowEnabled: true
                        shadowOpacity: 1
                        shadowColor: Appearance.m3colors.m3shadow
                    }

                    Image {
                        id: frozen
                        anchors.fill: parent
                        fillMode: Image.PreserveAspectFit
                        smooth: true
                        cache: false
                    }

                    Item {
                        id: darkOverlay
                        anchors.fill: parent
                        visible: (selection.hasSelection || selection.selecting) && !win.windowMode

                        Rectangle {
                            y: 0
                            width: parent.width
                            height: selection.sy
                            color: "black"
                            opacity: 0.5
                        }
                        Rectangle {
                            y: selection.sy + selection.h
                            width: parent.width
                            height: parent.height - (selection.sy + selection.h)
                            color: "black"
                            opacity: 0.5
                        }
                        Rectangle {
                            x: 0
                            y: selection.sy
                            width: selection.sx
                            height: selection.h
                            color: "black"
                            opacity: 0.5
                        }
                        Rectangle {
                            x: selection.sx + selection.w
                            y: selection.sy
                            width: parent.width - (selection.sx + selection.w)
                            height: selection.h
                            color: "black"
                            opacity: 0.5
                        }

                        Rectangle {
                            x: selection.sx
                            y: selection.sy
                            width: selection.w
                            height: selection.h
                            color: "black"
                            opacity: win.processing ? 0.6 : 0

                            Behavior on opacity {
                                NumberAnimation { duration: 200 }
                            }

                            LoadingIcon {
                                anchors.centerIn: parent
                                visible: win.processing
                            }
                        }
                    }

                    Rectangle {
                        id: outline
                        x: selection.sx
                        y: selection.sy
                        width: selection.w
                        height: selection.h
                        color: "transparent"
                        border.color: Appearance.m3colors.m3primary
                        border.width: 2
                        visible: (selection.selecting || selection.hasSelection) && !win.windowMode
                    }

                    Rectangle {
                        visible: selection.selecting
                        anchors.top: outline.bottom
                        anchors.topMargin: Metrics.margin(10)
                        anchors.horizontalCenter: outline.horizontalCenter
                        width: coords.width + 10
                        height: coords.height + 10
                        color: Appearance.m3colors.m3surface
                        radius: Metrics.radius(20)

                        StyledText {
                            id: coords
                            anchors.centerIn: parent
                            font.pixelSize: Metrics.fontSize(14)
                            animate: false
                            color: Appearance.m3colors.m3onSurface
                            property real scaleX: container.width / win.width
                            property real scaleY: container.height / win.height
                            text: Math.floor(selection.sx/scaleX) + "," + Math.floor(selection.sy/scaleY) + " " + Math.floor(selection.w/scaleX) + "x" + Math.floor(selection.h/scaleY)
                        }
                    }

                    MouseArea {
                        id: selection
                        anchors.fill: parent
                        enabled: win.ready && !win.windowMode

                        property real x1: 0
                        property real y1: 0
                        property real x2: 0
                        property real y2: 0
                        property bool selecting: false
                        property bool hasSelection: false

                        property real xp: 0
                        property real yp: 0
                        property real wp: 0
                        property real hp: 0

                        property real sx: xp * parent.width
                        property real sy: yp * parent.height
                        property real w: wp * parent.width
                        property real h: hp * parent.height

                        onPressed: mouse => {
                            if (!win.ready) return;
                            x1 = Math.max(0, Math.min(mouse.x, width));
                            y1 = Math.max(0, Math.min(mouse.y, height));
                            x2 = x1;
                            y2 = y1;
                            selecting = true;
                            hasSelection = false;
                        }

                        onPositionChanged: mouse => {
                            if (selecting) {
                                x2 = Math.max(0, Math.min(mouse.x, width));
                                y2 = Math.max(0, Math.min(mouse.y, height));
                                xp = Math.min(x1, x2) / width;
                                yp = Math.min(y1, y2) / height;
                                wp = Math.abs(x2 - x1) / width;
                                hp = Math.abs(y2 - y1) / height;
                            }
                        }

                        onReleased: mouse => {
                            if (!selecting) return;

                            x2 = Math.max(0, Math.min(mouse.x, width));
                            y2 = Math.max(0, Math.min(mouse.y, height));
                            selecting = false;

                            hasSelection = Math.abs(x2 - x1) > 5 && Math.abs(y2 - y1) > 5;

                            if (hasSelection) {
                                xp = Math.min(x1, x2) / width;
                                yp = Math.min(y1, y2) / height;
                                wp = Math.abs(x2 - x1) / width;
                                hp = Math.abs(y2 - y1) / height;

                                root.selectedRegion = Qt.rect(
                                    Math.min(x1, x2) * win.screen.width / width,
                                    Math.min(y1, y2) * win.screen.height / height,
                                    Math.abs(x2 - x1) * win.screen.width / width,
                                    Math.abs(y2 - y1) * win.screen.height / height
                                );

                                win.captureRegion();
                            } else {
                                win.close();
                            }
                        }
                    }

                    Repeater {
                        model: {
                            if (!win.windowMode || !win.ready) return [];
                            var ws = Hyprland.focusedMonitor?.activeWorkspace;
                            return ws?.toplevels ? ws.toplevels.values : [];
                        }

                        delegate: Item {
                            required property var modelData
                            property var w: modelData?.lastIpcObject
                            visible: w?.at && w?.size

                            property real barX: 0
                            property real barY: 0
                            property real sx: container.width / (win.screen.width - barX)
                            property real sy: container.height / (win.screen.height - barY)

                            x: visible ? (w.at[0] - barX) * sx : 0
                            y: visible ? (w.at[1] - barY) * sy : 0
                            width: visible ? w.size[0] * sx : 0
                            height: visible ? w.size[1] * sy : 0
                            z: w?.floating ? (hover.containsMouse ? 1000 : 100) : (hover.containsMouse ? 50 : 0)

                            Rectangle {
                                anchors.fill: parent
                                color: "transparent"
                                border.color: Appearance.m3colors.m3primary
                                border.width: hover.containsMouse ? 3 : 0
                                radius: Metrics.radius(8)
                                Behavior on border.width {
                                    NumberAnimation { duration: Metrics.chronoDuration(150) }
                                }
                            }

                            Rectangle {
                                anchors.fill: parent
                                color: Appearance.m3colors.m3primary
                                opacity: hover.containsMouse ? 0.15 : 0
                                radius: Metrics.radius(8)
                                Behavior on opacity {
                                    NumberAnimation { duration: Metrics.chronoDuration(150) }
                                }
                            }

                            MouseArea {
                                id: hover
                                anchors.fill: parent
                                hoverEnabled: true
                                cursorShape: Qt.PointingHandCursor
                                onClicked: {
                                    win.captureWindow(Qt.rect(w.at[0], w.at[1], w.size[0], w.size[1]));
                                }
                            }
                        }
                    }

                    ParallelAnimation {
                        running: win.visible && !win.closing && frozen.source != ""

                        NumberAnimation {
                            target: bg
                            property: "scale"
                            to: bg.scale + 0.05
                            duration: Metrics.chronoDuration("normal")
                            easing.type: Appearance.animation.easing
                        }
                        NumberAnimation {
                            target: container
                            property: "width"
                            to: win.width * 0.8
                            duration: Metrics.chronoDuration("normal")
                            easing.type: Appearance.animation.easing
                        }
                        NumberAnimation {
                            target: container
                            property: "height"
                            to: win.height * 0.8
                            duration: Metrics.chronoDuration("normal")
                            easing.type: Appearance.animation.easing
                        }
                    }

                    ParallelAnimation {
                        id: closeAnim

                        NumberAnimation {
                            target: bg
                            property: "scale"
                            to: bg.scale - 0.05
                            duration: Metrics.chronoDuration("normal")
                            easing.type: Appearance.animation.easing
                        }
                        NumberAnimation {
                            target: container
                            property: "width"
                            to: win.width
                            duration: Metrics.chronoDuration("normal")
                            easing.type: Appearance.animation.easing
                        }
                        NumberAnimation {
                            target: container
                            property: "height"
                            to: win.height
                            duration: Metrics.chronoDuration("normal")
                            easing.type: Appearance.animation.easing
                        }
                        NumberAnimation {
                            target: darkOverlay
                            property: "opacity"
                            to: 0
                            duration: Metrics.chronoDuration("normal")
                            easing.type: Appearance.animation.easing
                        }
                        NumberAnimation {
                            target: outline
                            property: "opacity"
                            to: 0
                            duration: Metrics.chronoDuration("normal")
                            easing.type: Appearance.animation.easing
                        }

                        onFinished: {
                            root.active = false;
                            if (win.savedSuccess) {
                                Quickshell.execDetached({
                                    command: ["notify-send", "Screenshot saved", win.savedPath.split("/").pop() + " (copied)"]
                                });
                            } else if (win.savedPath !== "") {
                                Quickshell.execDetached({
                                    command: ["notify-send", "Screenshot failed", "Could not save"]
                                });
                            }
                        }
                    }
                }

                Item {
                    anchors.horizontalCenter: parent.horizontalCenter
                    anchors.bottom: parent.bottom
                    anchors.bottomMargin: Metrics.margin(30)
                    width: row.width + 20
                    height: row.height + 20
		            visible: true

                    Rectangle {
                        anchors.fill: parent
                        color: Appearance.m3colors.m3surface
                        radius: Metrics.radius("large")
                    }

                    RowLayout {
                        id: row
                        anchors.centerIn: parent

                        StyledButton {
                            icon: "fullscreen"
                            text: "Full screen"
                            tooltipText: "Capture the whole screen [F]"
                            onClicked: win.captureFullscreen()
                        }
                        Rectangle {
                            Layout.fillHeight: true
                            width: 2
                            color: Appearance.m3colors.m3onSurfaceVariant
                            opacity: 0.2
                        }
                        StyledButton {
                            icon: "window"
                            checkable: true
                            checked: win.windowMode
                            text: "Window"
                            tooltipText: "Hover and click a window [W]"
                            onClicked: win.windowMode = !win.windowMode
                        }
                        StyledButton {
                            secondary: true
                            icon: "close"
                            tooltipText: "Exit [Escape]"
                            onClicked: win.close()
                        }
                    }
                }
            }

            HyprlandFocusGrab {
                id: grab
                windows: [win]
            }

            onVisibleChanged: {
                if (visible) grab.active = true
            }

            Connections {
                target: grab
                function onActiveChanged() {
                    if (!grab.active && !win.closing) win.close();
                }
            }
        }
    }
}
