import QtQuick
import QtQuick.Controls
import QtQuick.Templates as T
import qs.Commons

Item {
  id: root

  property color handleColor: Qt.alpha(Color.mHover, 0.8)
  property color handleHoverColor: handleColor
  property color handlePressedColor: handleColor
  property color trackColor: "transparent"
  property real handleWidth: Math.round(6 * Style.uiScaleRatio)
  property real handleRadius: Style.iRadiusM
  property int verticalPolicy: ScrollBar.AsNeeded
  property int horizontalPolicy: ScrollBar.AlwaysOff
  readonly property bool verticalScrollBarActive: {
    if (listView.ScrollBar.vertical.policy === ScrollBar.AlwaysOff)
      return false;
    return listView.contentHeight > listView.height;
  }
  readonly property bool contentOverflows: listView.contentHeight > listView.height

  property bool showGradientMasks: true
  property color gradientColor: Color.mSurfaceVariant
  property int gradientHeight: 16
  property bool reserveScrollbarSpace: true

  // Keep scrollbars visible whenever overflow exists (without forcing visibility when not scrollable)
  property bool showScrollbarWhenScrollable: Settings.data.ui.scrollbarAlwaysVisible

  // Available width for content (excludes scrollbar space when reserveScrollbarSpace is true)
  readonly property real availableWidth: width - (reserveScrollbarSpace ? handleWidth + Style.marginXS : 0)

  // Forward ListView properties
  property alias model: listView.model
  property alias delegate: listView.delegate
  property alias spacing: listView.spacing
  property alias orientation: listView.orientation
  property alias currentIndex: listView.currentIndex
  property alias count: listView.count
  property alias contentHeight: listView.contentHeight
  property alias contentWidth: listView.contentWidth
  property alias contentY: listView.contentY
  property alias contentX: listView.contentX
  property alias currentItem: listView.currentItem
  property alias highlightItem: listView.highlightItem
  property alias headerItem: listView.headerItem
  property alias footerItem: listView.footerItem
  property alias section: listView.section
  property alias highlightFollowsCurrentItem: listView.highlightFollowsCurrentItem
  property alias highlightMoveDuration: listView.highlightMoveDuration
  property alias highlightMoveVelocity: listView.highlightMoveVelocity
  property alias preferredHighlightBegin: listView.preferredHighlightBegin
  property alias preferredHighlightEnd: listView.preferredHighlightEnd
  property alias highlightRangeMode: listView.highlightRangeMode
  property alias snapMode: listView.snapMode
  property alias keyNavigationWraps: listView.keyNavigationWraps
  property alias cacheBuffer: listView.cacheBuffer
  property alias displayMarginBeginning: listView.displayMarginBeginning
  property alias displayMarginEnd: listView.displayMarginEnd
  property alias layoutDirection: listView.layoutDirection
  property alias effectiveLayoutDirection: listView.effectiveLayoutDirection
  property alias verticalLayoutDirection: listView.verticalLayoutDirection
  property alias boundsBehavior: listView.boundsBehavior
  property alias flickableDirection: listView.flickableDirection
  property alias interactive: listView.interactive
  property alias moving: listView.moving
  property alias flicking: listView.flicking
  property alias dragging: listView.dragging
  property alias horizontalVelocity: listView.horizontalVelocity
  property alias verticalVelocity: listView.verticalVelocity

  // Scroll speed multiplier for mouse wheel (1.0 = default, higher = faster)
  property real wheelScrollMultiplier: 2.0
  property int smoothWheelAnimationDuration: Style.animationNormal
  property real _wheelTargetY: 0

  function clampScrollY(value) {
    return Math.max(0, Math.min(value, listView.contentHeight - listView.height));
  }

  function applyWheelScroll(delta) {
    if (!root.contentOverflows)
      return;

    const step = delta * root.wheelScrollMultiplier;

    if (!Settings.data.general.smoothScrollEnabled || Settings.data.general.animationDisabled) {
      listView.contentY = root.clampScrollY(listView.contentY - step);
      root._wheelTargetY = listView.contentY;
      return;
    }

    if (!wheelScrollAnimation.running)
      root._wheelTargetY = listView.contentY;

    root._wheelTargetY = root.clampScrollY(root._wheelTargetY - step);
    wheelScrollAnimation.to = root._wheelTargetY;
    wheelScrollAnimation.restart();
  }

  function animateToContentY(targetY) {
    const clampedY = root.clampScrollY(targetY);

    if (!Settings.data.general.smoothScrollEnabled || Settings.data.general.animationDisabled || listView.dragging || listView.flicking) {
      listView.contentY = clampedY;
      root._wheelTargetY = clampedY;
      return;
    }

    root._wheelTargetY = clampedY;
    wheelScrollAnimation.to = clampedY;
    wheelScrollAnimation.restart();
  }

  // Forward ListView methods
  function positionViewAtIndex(index, mode) {
    const shouldAnimate = mode === ListView.Contain;
    if (!shouldAnimate) {
      listView.positionViewAtIndex(index, mode);
      root._wheelTargetY = listView.contentY;
      return;
    }

    const previousY = listView.contentY;
    listView.positionViewAtIndex(index, mode);
    const targetY = root.clampScrollY(listView.contentY);

    if (Math.abs(targetY - previousY) < 0.5) {
      root._wheelTargetY = targetY;
      return;
    }

    listView.contentY = previousY;
    root._wheelTargetY = previousY;
    root.animateToContentY(targetY);
  }

  function positionViewAtBeginning() {
    listView.positionViewAtBeginning();
  }

  function positionViewAtEnd() {
    listView.positionViewAtEnd();
  }

  function forceLayout() {
    listView.forceLayout();
  }

  function cancelFlick() {
    listView.cancelFlick();
  }

  function flick(xVelocity, yVelocity) {
    listView.flick(xVelocity, yVelocity);
  }

  function incrementCurrentIndex() {
    listView.incrementCurrentIndex();
  }

  function decrementCurrentIndex() {
    listView.decrementCurrentIndex();
  }

  function indexAt(x, y) {
    return listView.indexAt(x, y);
  }

  function itemAt(x, y) {
    return listView.itemAt(x, y);
  }

  function itemAtIndex(index) {
    return listView.itemAtIndex(index);
  }

  // Set reasonable implicit sizes for Layout usage
  implicitWidth: 200
  implicitHeight: 200

  Component.onCompleted: {
    _wheelTargetY = listView.contentY;
    createGradients();
  }

  // Dynamically create gradient overlays
  function createGradients() {
    if (!showGradientMasks)
      return;

    Qt.createQmlObject(`
      import QtQuick
      import qs.Commons
      Rectangle {
        x: 0
        y: 0
        width: root.availableWidth
        height: root.gradientHeight
        z: 1
        visible: root.showGradientMasks && root.contentOverflows
        opacity: {
          if (listView.contentY <= 1) return 0;
          if (listView.currentItem && listView.currentItem.y - listView.contentY < root.gradientHeight) return 0;
          return 1;
        }
        Behavior on opacity {
          NumberAnimation { duration: Style.animationFast; easing.type: Easing.InOutQuad }
        }
        gradient: Gradient {
          GradientStop { position: 0.0; color: root.gradientColor }
          GradientStop { position: 1.0; color: "transparent" }
        }
      }
    `, root, "topGradient");

    Qt.createQmlObject(`
      import QtQuick
      import qs.Commons
      Rectangle {
        x: 0
        anchors.bottom: parent.bottom
        anchors.bottomMargin: -1
        width: root.availableWidth
        height: root.gradientHeight + 1
        z: 1
        visible: root.showGradientMasks && root.contentOverflows
        opacity: {
          if (listView.contentY + listView.height >= listView.contentHeight - 1) return 0;
          if (listView.currentItem && listView.currentItem.y + listView.currentItem.height > listView.contentY + listView.height - root.gradientHeight) return 0;
          return 1;
        }
        Behavior on opacity {
          NumberAnimation { duration: Style.animationFast; easing.type: Easing.InOutQuad }
        }
        gradient: Gradient {
          GradientStop { position: 0.0; color: "transparent" }
          GradientStop { position: 1.0; color: root.gradientColor }
        }
      }
    `, root, "bottomGradient");
  }

  ListView {
    id: listView
    anchors.fill: parent
    anchors.rightMargin: root.reserveScrollbarSpace ? root.handleWidth + Style.marginXS : 0

    clip: true
    boundsBehavior: Flickable.StopAtBounds

    NumberAnimation {
      id: wheelScrollAnimation
      target: listView
      property: "contentY"
      duration: root.smoothWheelAnimationDuration
      easing.type: Easing.OutCubic
    }

    onDraggingChanged: {
      if (dragging) {
        wheelScrollAnimation.stop();
        root._wheelTargetY = contentY;
      }
    }

    onFlickingChanged: {
      if (flicking) {
        wheelScrollAnimation.stop();
        root._wheelTargetY = contentY;
      }
    }

    onContentHeightChanged: root._wheelTargetY = root.clampScrollY(root._wheelTargetY)
    onHeightChanged: root._wheelTargetY = root.clampScrollY(root._wheelTargetY)

    WheelHandler {
      enabled: !root.contentOverflows
      acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
      onWheel: event => {
                 event.accepted = true;
               }
    }

    WheelHandler {
      enabled: root.wheelScrollMultiplier !== 1.0 && root.contentOverflows
      acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
      onWheel: event => {
                 const delta = event.pixelDelta.y !== 0 ? event.pixelDelta.y : event.angleDelta.y / 2;
                 root.applyWheelScroll(delta);
                 event.accepted = true;
               }
    }

    ScrollBar.vertical: ScrollBar {
      parent: root
      x: root.mirrored ? 0 : root.width - width
      y: 0
      height: root.height
      policy: root.verticalPolicy
      visible: policy === ScrollBar.AlwaysOn || root.verticalScrollBarActive

      contentItem: Rectangle {
        implicitWidth: root.handleWidth
        implicitHeight: 100
        radius: root.handleRadius
        color: parent.pressed ? root.handlePressedColor : parent.hovered ? root.handleHoverColor : root.handleColor
        opacity: parent.policy === ScrollBar.AlwaysOn ? 1.0 : root.verticalScrollBarActive ? ((root.showScrollbarWhenScrollable || parent.active) ? 1.0 : 0.0) : 0.0

        Behavior on opacity {
          NumberAnimation {
            duration: Style.animationFast
          }
        }

        Behavior on color {
          ColorAnimation {
            duration: Style.animationFast
          }
        }
      }

      background: Rectangle {
        implicitWidth: root.handleWidth
        implicitHeight: 100
        color: root.trackColor
        opacity: parent.policy === ScrollBar.AlwaysOn ? 0.3 : root.verticalScrollBarActive ? ((root.showScrollbarWhenScrollable || parent.active) ? 0.3 : 0.0) : 0.0
        radius: root.handleRadius / 2

        Behavior on opacity {
          NumberAnimation {
            duration: Style.animationFast
          }
        }
      }
    }
  }
}
