import QtQuick
import qs.config
import qs.widgets
import "../../services/DisplayLayout.js" as DisplayLayout

Item {
    id: root

    required property var displayService
    property string selectedOutput: ""
    property var draftLayout: []
    property bool interactionEnabled: true

    signal selectionRequested(string output)

    implicitHeight: content.implicitHeight
    readonly property var canvasData: DisplayLayout.canvasRects(
        root.draftLayout, canvas.width, canvas.height, 18)

    function copied(layout): var {
        return (layout || []).map(record => Object.assign({}, record));
    }

    function resetDraft(): void {
        root.draftLayout = root.copied(root.displayService.currentLayout());
    }

    function setDraftPosition(output: string, x: real, y: real, snapToEdges: bool): bool {
        const next = root.copied(root.draftLayout);
        const record = next.find(candidate => candidate.name === output);
        if (!record)
            return false;
        record.x = Math.round(x);
        record.y = Math.round(y);
        root.draftLayout = snapToEdges ? DisplayLayout.snap(next, output, 16) : next;
        return true;
    }

    function nudge(output: string, dx: int, dy: int): bool {
        const record = root.draftLayout.find(candidate => candidate.name === output);
        return !!record && root.setDraftPosition(output, record.x + dx, record.y + dy, false);
    }

    function applyDraft(): bool {
        return root.displayService.applyLayout(root.copied(root.draftLayout));
    }

    function makePrimary(output: string): bool {
        const next = root.copied(root.draftLayout);
        if (!next.some(record => record.name === output))
            return false;
        for (const record of next)
            record.primary = record.name === output;
        root.draftLayout = DisplayLayout.normalize(next);
        return root.applyDraft();
    }

    function canvasSnapshot(): var {
        return {
            bounds: root.canvasData.bounds,
            scale: root.canvasData.scale,
            rects: root.canvasData.rects.map(record => Object.assign({}, record))
        };
    }

    Component.onCompleted: root.resetDraft()

    Connections {
        target: root.displayService
        ignoreUnknownSignals: true
        function onMonitorsChanged(): void {
            if (!root.displayService.awaitingConfirmation)
                root.resetDraft();
        }
    }

    Column {
        id: content
        width: parent.width
        spacing: 11

        Rectangle {
            id: canvas
            width: parent.width
            height: root.width >= 620 ? 232 : 190
            radius: Theme.cardRadius
            color: Theme.alpha(Theme.bgDark, 0.76)
            border.width: 1
            border.color: Theme.alpha(Theme.fg, 0.07)
            clip: true

            // A restrained coordinate field makes the topology feel like a
            // precision instrument without turning it into a technical graph.
            Repeater {
                model: 4
                Rectangle {
                    required property int index
                    y: (index + 1) * canvas.height / 5
                    width: canvas.width
                    height: 1
                    color: Theme.alpha(Theme.fg, 0.025)
                }
            }

            Repeater {
                model: root.canvasData.rects

                Rectangle {
                    id: tile

                    required property var modelData
                    readonly property bool selected: root.selectedOutput === modelData.name
                    readonly property var draft: root.draftLayout.find(
                        record => record.name === modelData.name)

                    x: modelData.x
                    y: modelData.y
                    width: Math.max(64, modelData.width)
                    height: Math.max(48, modelData.height)
                    radius: 11
                    color: tile.selected
                        ? Theme.alpha(Theme.bgHighlight, 0.92)
                        : Theme.alpha(Theme.bgPanel, hover.hovered ? 0.94 : 0.78)
                    border.width: tile.selected || activeFocus ? 2 : 1
                    border.color: activeFocus
                        ? Theme.accentSecondary
                        : (tile.selected ? Theme.accent : Theme.alpha(Theme.fg, 0.14))
                    opacity: root.interactionEnabled ? 1 : 0.5
                    activeFocusOnTab: root.interactionEnabled

                    Accessible.role: Accessible.Button
                    Accessible.name: "Move " + tile.modelData.name
                    Accessible.description: tile.draft && tile.draft.primary
                        ? "Primary display. Drag or use the arrow keys to move it."
                        : "Drag or use the arrow keys to move this display."

                    Rectangle {
                        anchors.fill: parent
                        anchors.margins: 2
                        radius: parent.radius - 2
                        visible: tile.selected
                        opacity: 0.24
                        gradient: Gradient {
                            orientation: Gradient.Horizontal
                            GradientStop { position: 0; color: Theme.accent }
                            GradientStop { position: 1; color: Theme.accentSecondary }
                        }
                    }

                    Column {
                        anchors.left: parent.left
                        anchors.right: parent.right
                        anchors.verticalCenter: parent.verticalCenter
                        anchors.margins: 11
                        spacing: 2

                        Text {
                            width: parent.width
                            text: tile.modelData.name
                            color: Theme.fg
                            font.family: Theme.fontFamily
                            font.pixelSize: Theme.fontSize
                            font.weight: Font.DemiBold
                            elide: Text.ElideRight
                        }
                        Text {
                            width: parent.width
                            text: tile.draft
                                ? `${Math.round(tile.draft.width / tile.draft.scale)} × ${Math.round(tile.draft.height / tile.draft.scale)}`
                                : ""
                            color: Theme.fgDim
                            font.family: Theme.fontFamily
                            font.features: Theme.tabularFigures
                            font.pixelSize: Theme.fontSizeSmall
                            elide: Text.ElideRight
                        }
                    }

                    Rectangle {
                        anchors.top: parent.top
                        anchors.right: parent.right
                        anchors.margins: 7
                        width: primaryText.implicitWidth + 12
                        height: 20
                        radius: Theme.pillRadius
                        visible: tile.draft && tile.draft.primary
                        color: Theme.alpha(Theme.accent, 0.2)

                        Text {
                            id: primaryText
                            anchors.centerIn: parent
                            text: "Primary"
                            color: Theme.accentAlt
                            font.family: Theme.fontFamily
                            font.pixelSize: Math.max(9, Theme.fontSizeSmall - 1)
                            font.weight: Font.DemiBold
                        }
                    }

                    HoverHandler {
                        id: hover
                        enabled: root.interactionEnabled
                        cursorShape: Qt.OpenHandCursor
                    }

                    TapHandler {
                        enabled: root.interactionEnabled
                        onTapped: {
                            root.selectionRequested(tile.modelData.name);
                            tile.forceActiveFocus();
                        }
                    }

                    DragHandler {
                        id: drag
                        target: null
                        enabled: root.interactionEnabled
                        property real initialX: 0
                        property real initialY: 0
                        property bool moved: false

                        onActiveChanged: {
                            if (active) {
                                const record = root.draftLayout.find(
                                    candidate => candidate.name === tile.modelData.name);
                                initialX = record ? record.x : 0;
                                initialY = record ? record.y : 0;
                                moved = false;
                                root.selectionRequested(tile.modelData.name);
                                tile.forceActiveFocus();
                            } else if (moved) {
                                const record = root.draftLayout.find(
                                    candidate => candidate.name === tile.modelData.name);
                                if (record) {
                                    root.setDraftPosition(tile.modelData.name, record.x, record.y, true);
                                    root.applyDraft();
                                }
                            }
                        }
                        onTranslationChanged: {
                            if (!active || root.canvasData.scale <= 0)
                                return;
                            moved = true;
                            root.setDraftPosition(
                                tile.modelData.name,
                                initialX + translation.x / root.canvasData.scale,
                                initialY + translation.y / root.canvasData.scale,
                                false);
                        }
                    }

                    Keys.onPressed: event => {
                        if (!root.interactionEnabled)
                            return;
                        const step = event.modifiers & Qt.ShiftModifier ? 100 : 10;
                        let handled = true;
                        if (event.key === Qt.Key_Left)
                            root.nudge(tile.modelData.name, -step, 0);
                        else if (event.key === Qt.Key_Right)
                            root.nudge(tile.modelData.name, step, 0);
                        else if (event.key === Qt.Key_Up)
                            root.nudge(tile.modelData.name, 0, -step);
                        else if (event.key === Qt.Key_Down)
                            root.nudge(tile.modelData.name, 0, step);
                        else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter)
                            root.applyDraft();
                        else if (event.key === Qt.Key_Escape)
                            root.resetDraft();
                        else
                            handled = false;
                        event.accepted = handled;
                    }
                }
            }
        }

        Row {
            width: parent.width
            spacing: 8

            Text {
                width: Math.max(0, parent.width - identifyButton.width
                    - primaryButton.width - applyButton.width - 24)
                anchors.verticalCenter: parent.verticalCenter
                text: root.width >= 600
                    ? "Drag to arrange · arrows move 10 px · Shift moves 100 px"
                    : "Drag or use the arrow keys"
                color: Theme.fgMuted
                font.family: Theme.fontFamily
                font.pixelSize: Theme.fontSizeSmall
                elide: Text.ElideRight
            }

            SettingsButton {
                id: identifyButton
                text: "Identify"
                enabled: root.interactionEnabled
                onClicked: root.displayService.identify()
            }

            SettingsButton {
                id: primaryButton
                text: "Make primary"
                enabled: root.interactionEnabled && root.selectedOutput !== ""
                    && !root.draftLayout.find(record =>
                        record.name === root.selectedOutput)?.primary
                onClicked: root.makePrimary(root.selectedOutput)
            }

            SettingsButton {
                id: applyButton
                text: "Apply"
                enabled: root.interactionEnabled
                onClicked: root.applyDraft()
            }
        }
    }
}
