// A light dimmer that previews locally and sends one value when interaction
// ends. Home Assistant never sees the intermediate pointer positions.

import QtQuick
import qs.config

Item {
    id: root

    property int value: 0
    property int previewValue: 0
    property bool interactionActive: false
    property string accessibleName: "Brightness"

    readonly property bool pressed: root.interactionActive

    signal previewChanged(int value)
    signal committed(int value)

    implicitWidth: 160
    implicitHeight: 32
    activeFocusOnTab: root.enabled
    opacity: root.enabled ? 1 : 0.42

    Accessible.role: Accessible.Slider
    Accessible.name: root.accessibleName
    // Qt 6.11's installed Accessible attached type has no structured value or
    // range properties, so expose both in the supported live description.
    Accessible.description: root.previewValue + " percent, range 0 to 100"
    Accessible.focusable: root.enabled
    Accessible.focused: root.activeFocus
    Accessible.onIncreaseAction: root.commitStep(5)
    Accessible.onDecreaseAction: root.commitStep(-5)

    onValueChanged: {
        if (!root.interactionActive)
            root.updatePreview(root.value, false);
    }

    Component.onCompleted: root.updatePreview(root.value, false)

    Keys.onLeftPressed: root.commitStep(-5)
    Keys.onDownPressed: root.commitStep(-5)
    Keys.onRightPressed: root.commitStep(5)
    Keys.onUpPressed: root.commitStep(5)

    Rectangle {
        id: track
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.verticalCenter: parent.verticalCenter
        height: 10
        radius: 5
        color: Theme.alpha(Theme.fg, 0.105)
        border.width: root.activeFocus ? 1 : 0
        border.color: Theme.alpha(Theme.warn, 0.72)

        Rectangle {
            id: fill
            anchors.left: parent.left
            anchors.top: parent.top
            anchors.bottom: parent.bottom
            width: track.width * root.previewValue / 100
            radius: track.radius
            color: Theme.warn

            Behavior on width {
                enabled: !root.interactionActive
                NumberAnimation {
                    duration: Theme.durFast
                    easing.type: Easing.OutQuad
                }
            }
        }

        Rectangle {
            id: knob
            anchors.verticalCenter: parent.verticalCenter
            x: Math.max(0, Math.min(track.width - width,
                track.width * root.previewValue / 100 - width / 2))
            width: 16
            height: 16
            radius: 8
            color: Theme.fg
            border.width: 1
            border.color: Theme.alpha(Theme.bgDark, 0.38)
        }
    }

    // The 32 px interaction surface is intentionally much taller than the
    // 10 px track, while remaining inside this component's layout bounds.
    MouseArea {
        id: drag
        anchors.fill: parent
        enabled: root.enabled
        hoverEnabled: true
        cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor

        onPressed: event => {
            root.forceActiveFocus();
            root.beginPointerInteraction(event.x);
            event.accepted = true;
        }
        onPositionChanged: event => root.movePointerInteraction(event.x)
        onReleased: event => {
            root.releasePointerInteraction();
            event.accepted = true;
        }
        onCanceled: root.cancelPointerInteraction()
        onWheel: event => {
            root.commitWheel(event.angleDelta.y);
            event.accepted = true;
        }
    }

    function clamp(candidate: real): int {
        return Math.max(0, Math.min(100, Math.round(candidate)));
    }

    function updatePreview(candidate: real, announce: bool): void {
        const nextValue = root.clamp(candidate);
        if (root.previewValue === nextValue)
            return;
        root.previewValue = nextValue;
        if (announce)
            root.previewChanged(nextValue);
    }

    function previewAt(pointerX: real): void {
        root.updatePreview(pointerX / Math.max(1, drag.width) * 100, true);
    }

    function beginPointerInteraction(pointerX: real): void {
        if (!root.enabled)
            return;
        root.interactionActive = true;
        root.previewAt(pointerX);
    }

    function movePointerInteraction(pointerX: real): void {
        if (root.interactionActive)
            root.previewAt(pointerX);
    }

    function releasePointerInteraction(): void {
        if (!root.interactionActive)
            return;
        root.interactionActive = false;
        root.committed(root.previewValue);
    }

    function cancelPointerInteraction(): void {
        root.interactionActive = false;
        root.updatePreview(root.value, false);
    }

    function commitWheel(delta: int): void {
        if (delta === 0)
            return;
        root.commitStep(delta > 0 ? 5 : -5);
    }

    function commitStep(delta: int): void {
        if (!root.enabled)
            return;
        root.updatePreview(root.previewValue + delta, true);
        root.committed(root.previewValue);
    }
}
