// SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later

import QtQuick

import org.kde.plasma.private.volume

QtObject {
    id: root

    property SinkModel paSinkModel: SinkModel {}

    // whether the audio icon should be visible in the status bar
    readonly property bool isVisible: paSinkModel.preferredSink

    // the icon that should be displayed in the status bar
    readonly property string icon: paSinkModel.preferredSink && !isDummyOutput(paSinkModel.preferredSink)
                                    ? iconName(paSinkModel.preferredSink.volume, paSinkModel.preferredSink.muted)
                                    : iconName(0, true)

    // the name of the audio device when it isn't valid
    readonly property string dummyOutputName: "auto_null"

    // the maximum volume amount
    readonly property int maxVolumeValue: Math.round(100 * PulseAudio.NormalVolume / 100.0)

    // step that increments when adjusting the volume
    readonly property int volumeStep: Math.round(5 * PulseAudio.NormalVolume / 100.0)

    // The current audio volume (updated by connecting to sinks)
    property int volumeValue

    function isDummyOutput(output) {
        return output && output.name === dummyOutputName;
    }

    function boundVolume(volume) {
        return Math.max(PulseAudio.MinimalVolume, Math.min(volume, maxVolumeValue));
    }

    function volumePercent(volume, max){
        if (!max) {
            max = PulseAudio.NormalVolume;
        }
        return Math.round(volume / max * 100.0);
    }

    function increaseVolume() {
        if (!paSinkModel.preferredSink || isDummyOutput(paSinkModel.preferredSink)) {
            return;
        }

        var volume = boundVolume(paSinkModel.preferredSink.volume + volumeStep);
        var percent = volumePercent(volume, maxVolumeValue);
        paSinkModel.preferredSink.muted = percent == 0;
        paSinkModel.preferredSink.volume = volume;
    }

    function decreaseVolume() {
        if (!paSinkModel.preferredSink || isDummyOutput(paSinkModel.preferredSink)) {
            return;
        }

        var volume = boundVolume(paSinkModel.preferredSink.volume - volumeStep);
        var percent = volumePercent(volume, maxVolumeValue);
        paSinkModel.preferredSink.muted = percent == 0;
        paSinkModel.preferredSink.volume = volume;
    }

    function muteVolume() {
        if (!paSinkModel.preferredSink || isDummyOutput(paSinkModel.preferredSink)) {
            return;
        }

        paSinkModel.preferredSink.muted = !paSinkModel.preferredSink.muted;
    }

    function iconName(volume, muted, prefix) {
        if (!prefix) {
            prefix = "audio-volume";
        }
        var icon = null;
        var percent = volume / maxVolumeValue;
        if (percent <= 0.0 || muted) {
            icon = prefix + "-muted";
        } else if (percent <= 0.25) {
            icon = prefix + "-low";
        } else if (percent <= 0.75) {
            icon = prefix + "-medium";
        } else {
            icon = prefix + "-high";
        }
        return icon;
    }

    // emitted when the volume changed, but not due to sink switching
    signal volumeChanged()

    property var updateVolume: Connections {
        target: root.paSinkModel ? (root.paSinkModel.preferredSink ? root.paSinkModel.preferredSink : null) : null
        enabled: target !== null

        function onVolumeChanged() {
            root.volumeValue = root.volumePercent(root.paSinkModel.preferredSink.volume, root.maxVolumeValue);
            root.volumeChanged();
        }

        function onMutedChanged() {
            root.volumeValue = root.paSinkModel.preferredSink.muted ? 0 : root.volumePercent(root.paSinkModel.preferredSink.volume, root.maxVolumeValue);
            root.volumeChanged();
        }
    }

    property var updateVolumeOnSinkChange: Connections {
        target: root.paSinkModel ? root.paSinkModel : null
        enabled: target !== null

        function onPreferredSinkChanged() {
            if (root.paSinkModel.preferredSink) {
                root.volumeValue = root.volumePercent(root.paSinkModel.preferredSink.volume, root.maxVolumeValue);
            }
        }
    }
}
