import QtQuick
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Services.Media
import qs.Widgets

// Audio controls card: output and input volume controls
NBox {
  id: root

  property real localOutputVolume: 0
  property bool localOutputVolumeChanging: false
  property int lastSinkId: -1

  property real localInputVolume: 0
  property bool localInputVolumeChanging: false
  property int lastSourceId: -1

  readonly property bool outputVolumeGuard: outputVolumeSlider.sliderActive || localOutputVolumeChanging
  readonly property bool inputVolumeGuard: inputVolumeSlider.sliderActive || localInputVolumeChanging

  Component.onCompleted: {
    var vol = AudioService.volume;
    localOutputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0;
    var inputVol = AudioService.inputVolume;
    localInputVolume = (inputVol !== undefined && !isNaN(inputVol)) ? inputVol : 0;
    if (AudioService.sink) {
      lastSinkId = AudioService.sink.id;
    }
    if (AudioService.source) {
      lastSourceId = AudioService.source.id;
    }
  }

  // Reset local volume when device changes - use current device's volume
  Connections {
    target: AudioService
    function onSinkChanged() {
      if (AudioService.sink) {
        const newSinkId = AudioService.sink.id;
        if (newSinkId !== lastSinkId) {
          lastSinkId = newSinkId;
          // Immediately set local volume to current device's volume
          var vol = AudioService.volume;
          localOutputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0;
        }
      } else {
        lastSinkId = -1;
        localOutputVolume = 0;
      }
    }
  }

  Connections {
    target: AudioService
    function onSourceChanged() {
      if (AudioService.source) {
        const newSourceId = AudioService.source.id;
        if (newSourceId !== lastSourceId) {
          lastSourceId = newSourceId;
          // Immediately set local volume to current device's volume
          var vol = AudioService.inputVolume;
          localInputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0;
        }
      } else {
        lastSourceId = -1;
        localInputVolume = 0;
      }
    }
  }

  // Timer to debounce volume changes
  // Only sync if the device hasn't changed (check by comparing IDs)
  Timer {
    interval: 100
    running: true
    repeat: true
    onTriggered: {
      // Only sync if sink hasn't changed
      if (AudioService.sink && AudioService.sink.id === lastSinkId) {
        if (Math.abs(localOutputVolume - AudioService.volume) >= 0.01) {
          AudioService.setVolume(localOutputVolume);
        }
      }
      // Only sync if source hasn't changed
      if (AudioService.source && AudioService.source.id === lastSourceId) {
        if (Math.abs(localInputVolume - AudioService.inputVolume) >= 0.01) {
          AudioService.setInputVolume(localInputVolume);
        }
      }
    }
  }

  Connections {
    target: AudioService
    function onVolumeChanged() {
      if (!outputVolumeGuard && !AudioService.isSettingOutputVolume && AudioService.sink && AudioService.sink.id === lastSinkId) {
        var vol = AudioService.volume;
        localOutputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0;
      }
    }
  }

  Connections {
    target: AudioService
    function onInputVolumeChanged() {
      if (!inputVolumeGuard && !AudioService.isSettingInputVolume && AudioService.source && AudioService.source.id === lastSourceId) {
        var vol = AudioService.inputVolume;
        localInputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0;
      }
    }
  }

  Connections {
    target: outputVolumeSlider
    function onSliderActiveChanged() {
      if (!outputVolumeSlider.sliderActive && AudioService.sink && AudioService.sink.id === lastSinkId) {
        var vol = AudioService.volume;
        localOutputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0;
      }
    }
  }

  Connections {
    target: inputVolumeSlider
    function onSliderActiveChanged() {
      if (!inputVolumeSlider.sliderActive && AudioService.source && AudioService.source.id === lastSourceId) {
        var vol = AudioService.inputVolume;
        localInputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0;
      }
    }
  }

  RowLayout {
    anchors.fill: parent
    anchors.margins: Style.marginM
    spacing: Style.marginM

    // Output Volume Section
    ColumnLayout {
      spacing: Style.marginXXS
      Layout.fillWidth: true
      Layout.preferredWidth: 0
      opacity: AudioService.sink ? 1.0 : 0.5
      enabled: AudioService.sink

      // Output Volume Header
      RowLayout {
        Layout.fillWidth: true
        spacing: Style.marginXS

        NIconButton {
          icon: AudioService.muted ? "volume-off" : "volume-high"
          baseSize: Style.baseWidgetSize * 0.5
          colorFg: AudioService.muted ? Color.mError : Color.mOnSurface
          colorBg: "transparent"
          colorBgHover: Color.mHover
          colorFgHover: Color.mOnHover
          onClicked: AudioService.setOutputMuted(!AudioService.muted)
        }

        NText {
          text: AudioService.sink ? AudioService.sink.description : "No output device"
          pointSize: Style.fontSizeXS
          color: Color.mOnSurfaceVariant
          elide: Text.ElideRight
          Layout.fillWidth: true
          Layout.preferredWidth: 0
        }
      }

      // Output Volume Slider
      NSlider {
        id: outputVolumeSlider
        Layout.fillWidth: true
        from: 0
        to: Settings.data.audio.volumeOverdrive ? 1.5 : 1.0
        value: localOutputVolume
        stepSize: 0.01
        heightRatio: 0.5
        onMoved: localOutputVolume = value
        onPressedChanged: localOutputVolumeChanging = pressed
        tooltipText: `${Math.round((outputVolumeGuard ? localOutputVolume : AudioService.volume) * 100)}%`
        tooltipDirection: "bottom"

        // MouseArea to handle wheel events when hovering over the slider
        MouseArea {
          anchors.fill: parent
          hoverEnabled: true
          acceptedButtons: Qt.NoButton
          propagateComposedEvents: true

          onWheel: wheel => {
                     if (outputVolumeSlider.enabled && AudioService.sink) {
                       const delta = wheel.angleDelta.y || wheel.angleDelta.x;
                       const step = Settings.data.audio.volumeStep / 100.0; // Convert percentage to 0-1 range
                       const increment = delta > 0 ? step : -step;
                       const maxVolume = Settings.data.audio.volumeOverdrive ? 1.5 : 1.0;
                       const newValue = Math.max(0, Math.min(maxVolume, localOutputVolume + increment));
                       localOutputVolume = newValue;
                     }
                   }
        }
      }
    }

    // Input Volume Section
    ColumnLayout {
      spacing: Style.marginXXS
      Layout.fillWidth: true
      Layout.preferredWidth: 0
      opacity: AudioService.source ? 1.0 : 0.5
      enabled: AudioService.source

      // Input Volume Header
      RowLayout {
        Layout.fillWidth: true
        spacing: Style.marginXS

        NIconButton {
          icon: AudioService.inputMuted ? "microphone-off" : "microphone"
          baseSize: Style.baseWidgetSize * 0.5
          colorFg: AudioService.inputMuted ? Color.mError : Color.mOnSurface
          colorBg: "transparent"
          colorBgHover: Color.mHover
          colorFgHover: Color.mOnHover
          onClicked: AudioService.setInputMuted(!AudioService.inputMuted)
        }

        NText {
          text: AudioService.source ? AudioService.source.description : "No input device"
          pointSize: Style.fontSizeXS
          color: Color.mOnSurfaceVariant
          elide: Text.ElideRight
          Layout.fillWidth: true
          Layout.preferredWidth: 0
        }
      }

      // Input Volume Slider
      NSlider {
        id: inputVolumeSlider
        Layout.fillWidth: true
        from: 0
        to: Settings.data.audio.volumeOverdrive ? 1.5 : 1.0
        value: localInputVolume
        stepSize: 0.01
        heightRatio: 0.5
        onMoved: localInputVolume = value
        onPressedChanged: localInputVolumeChanging = pressed
        tooltipText: `${Math.round((inputVolumeGuard ? localInputVolume : AudioService.inputVolume) * 100)}%`
        tooltipDirection: "bottom"

        // MouseArea to handle wheel events when hovering over the slider
        MouseArea {
          anchors.fill: parent
          hoverEnabled: true
          acceptedButtons: Qt.NoButton
          propagateComposedEvents: true

          onWheel: wheel => {
                     if (inputVolumeSlider.enabled && AudioService.source) {
                       const delta = wheel.angleDelta.y || wheel.angleDelta.x;
                       const step = Settings.data.audio.volumeStep / 100.0; // Convert percentage to 0-1 range
                       const increment = delta > 0 ? step : -step;
                       const maxVolume = Settings.data.audio.volumeOverdrive ? 1.5 : 1.0;
                       const newValue = Math.max(0, Math.min(maxVolume, localInputVolume + increment));
                       localInputVolume = newValue;
                     }
                   }
        }
      }
    }
  }
}
