import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Modules.Bar.Extras
import qs.Services.Media
import qs.Services.UI
import qs.Widgets
import qs.Widgets.AudioSpectrum

Item {
  id: root

  property ShellScreen screen
  property string widgetId: ""
  property string section: ""
  property int sectionWidgetIndex: -1
  property int sectionWidgetsCount: 0

  // Settings
  property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId] ?? {}
  // Explicit screenName property ensures reactive binding when screen changes
  readonly property string screenName: screen ? screen.name : ""
  property var widgetSettings: {
    if (section && sectionWidgetIndex >= 0 && screenName) {
      var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
      if (widgets && sectionWidgetIndex < widgets.length) {
        return widgets[sectionWidgetIndex];
      }
    }
    return {};
  }

  // Bar orientation (per-screen)
  readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
  readonly property bool isVertical: barPosition === "left" || barPosition === "right"
  readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screenName)
  readonly property real barFontSize: Style.getBarFontSizeForScreen(screenName)

  // Widget settings
  readonly property string hideMode: widgetSettings.hideMode !== undefined ? widgetSettings.hideMode : widgetMetadata.hideMode
  readonly property bool hideWhenIdle: widgetSettings.hideWhenIdle !== undefined ? widgetSettings.hideWhenIdle : widgetMetadata.hideWhenIdle
  readonly property bool showAlbumArt: widgetSettings.showAlbumArt !== undefined ? widgetSettings.showAlbumArt : widgetMetadata.showAlbumArt
  readonly property bool showArtistFirst: widgetSettings.showArtistFirst !== undefined ? widgetSettings.showArtistFirst : widgetMetadata.showArtistFirst
  readonly property bool showVisualizer: widgetSettings.showVisualizer !== undefined ? widgetSettings.showVisualizer : widgetMetadata.showVisualizer
  readonly property string visualizerType: widgetSettings.visualizerType !== undefined ? widgetSettings.visualizerType : widgetMetadata.visualizerType
  readonly property string scrollingMode: widgetSettings.scrollingMode !== undefined ? widgetSettings.scrollingMode : widgetMetadata.scrollingMode
  readonly property bool showProgressRing: widgetSettings.showProgressRing !== undefined ? widgetSettings.showProgressRing : widgetMetadata.showProgressRing
  readonly property bool useFixedWidth: widgetSettings.useFixedWidth !== undefined ? widgetSettings.useFixedWidth : widgetMetadata.useFixedWidth
  readonly property real maxWidth: widgetSettings.maxWidth !== undefined ? widgetSettings.maxWidth : Math.max(widgetMetadata.maxWidth, screen ? screen.width * 0.06 : 0)
  readonly property string textColorKey: widgetSettings.textColor !== undefined ? widgetSettings.textColor : widgetMetadata.textColor
  readonly property color textColor: Color.resolveColorKey(textColorKey)

  // Dimensions
  readonly property int artSize: Style.toOdd(capsuleHeight * 0.75)
  readonly property int iconSize: Style.toOdd(capsuleHeight * 0.75)
  readonly property int verticalSize: Style.toOdd(capsuleHeight * 0.85)
  readonly property int progressWidth: 2

  // State
  readonly property bool hasPlayer: MediaService.currentPlayer !== null
  readonly property bool shouldHideIdle: (hideMode === "idle" || hideWhenIdle) && !MediaService.isPlaying
  readonly property bool shouldHideEmpty: !hasPlayer && hideMode === "hidden"
  readonly property bool isHidden: shouldHideIdle || shouldHideEmpty

  // Title
  readonly property string title: {
    if (!hasPlayer)
      return I18n.tr("bar.media-mini.no-active-player");
    var artist = MediaService.trackArtist;
    var track = MediaService.trackTitle;
    return showArtistFirst ? (artist ? `${artist} - ${track}` : track) : (artist ? `${track} - ${artist}` : track);
  }

  // SpectrumService registration for visualizer
  readonly property string spectrumComponentId: "bar:mediamini:" + root.screen?.name + ":" + root.section + ":" + root.sectionWidgetIndex
  readonly property bool needsSpectrum: root.showVisualizer && root.visualizerType !== "" && root.visualizerType !== "none" && !root.isHidden

  Layout.preferredHeight: isVertical ? -1 : Style.getBarHeightForScreen(screenName)
  Layout.preferredWidth: isVertical ? Style.getBarHeightForScreen(screenName) : -1
  Layout.fillHeight: false
  Layout.fillWidth: false

  onNeedsSpectrumChanged: {
    if (root.needsSpectrum) {
      SpectrumService.registerComponent(root.spectrumComponentId);
    } else {
      SpectrumService.unregisterComponent(root.spectrumComponentId);
    }
  }

  Component.onCompleted: {
    if (root.needsSpectrum) {
      SpectrumService.registerComponent(root.spectrumComponentId);
    }
  }

  Component.onDestruction: {
    SpectrumService.unregisterComponent(root.spectrumComponentId);
  }

  // Layout
  // For horizontal bars, height is always capsuleHeight (no animation needed to prevent jitter)
  // For vertical bars, collapse to 0 when hidden
  implicitWidth: isVertical ? (isHidden ? 0 : verticalSize) : (isHidden ? 0 : contentWidth)
  implicitHeight: isVertical ? (isHidden ? 0 : verticalSize) : capsuleHeight
  visible: !shouldHideIdle && (hideMode !== "hidden" || opacity > 0)
  opacity: isHidden ? 0.0 : ((hideMode === "transparent" && !hasPlayer) ? 0.0 : 1.0)

  property real mainContentWidth: 0
  readonly property real contentWidth: {
    if (useFixedWidth)
      return maxWidth;

    // Calculate icon/art width (must match RowLayout visibility)
    var iconWidth = 0;
    if (!hasPlayer) {
      iconWidth = iconSize;
    } else if (showAlbumArt || showProgressRing) {
      iconWidth = artSize;
    }

    var margins = isVertical ? 0 : Style.margin2S;

    // Add spacing and text width
    var textWidth = 0;
    if (titleContainer.measuredWidth > 0) {
      if (iconWidth > 0)
        margins += Style.marginS;
      textWidth = titleContainer.measuredWidth + Style.margin2XXS;
    }

    var total = iconWidth + textWidth + margins;

    // calculate the width of all elements except the scrolling text
    mainContentWidth = total - textWidth;

    return hasPlayer ? Math.min(total, maxWidth) : total;
  }

  Behavior on opacity {
    NumberAnimation {
      duration: Style.animationNormal
      easing.type: Easing.InOutCubic
    }
  }
  Behavior on implicitWidth {
    NumberAnimation {
      duration: Style.animationNormal
      easing.type: Easing.InOutCubic
    }
  }
  Behavior on implicitHeight {
    NumberAnimation {
      duration: Style.animationNormal
      easing.type: Easing.InOutCubic
    }
  }

  // Context menu
  NPopupContextMenu {
    id: contextMenu
    model: {
      var items = [];
      if (hasPlayer && MediaService.canPlay) {
        items.push({
                     "label": MediaService.isPlaying ? I18n.tr("common.pause") : I18n.tr("common.play"),
                     "action": "play-pause",
                     "icon": MediaService.isPlaying ? "media-pause" : "media-play"
                   });
      }
      if (hasPlayer && MediaService.canGoPrevious) {
        items.push({
                     "label": I18n.tr("common.previous"),
                     "action": "previous",
                     "icon": "media-prev"
                   });
      }
      if (hasPlayer && MediaService.canGoNext) {
        items.push({
                     "label": I18n.tr("common.next"),
                     "action": "next",
                     "icon": "media-next"
                   });
      }

      // Append available players (like in Control Center) so user can switch from the bar
      var players = MediaService.getAvailablePlayers ? MediaService.getAvailablePlayers() : [];
      if (players && players.length > 1) {
        for (var i = 0; i < players.length; i++) {
          var isCurrent = (i === MediaService.selectedPlayerIndex);
          items.push({
                       "label": players[i].identity,
                       "action": "player-" + i,
                       "icon": isCurrent ? "check" : "disc",
                       "enabled": true,
                       "visible": true
                     });
        }
      }

      items.push({
                   "label": I18n.tr("actions.widget-settings"),
                   "action": "widget-settings",
                   "icon": "settings"
                 });
      return items;
    }

    onTriggered: action => {
                   contextMenu.close();
                   PanelService.closeContextMenu(screen);

                   if (action === "play-pause")
                   MediaService.playPause();
                   else if (action === "previous")
                   MediaService.previous();
                   else if (action === "next")
                   MediaService.next();
                   else if (action && action.indexOf("player-") === 0) {
                     var idx = parseInt(action.split("-")[1]);
                     if (!isNaN(idx)) {
                       MediaService.switchToPlayer(idx);
                     }
                   } else if (action === "widget-settings") {
                     BarService.openWidgetSettings(screen, section, sectionWidgetIndex, widgetId, widgetSettings);
                   }
                 }
  }

  // Main container - stays at content size, pixel-perfect centered in parent
  Rectangle {
    id: container
    x: Style.pixelAlignCenter(parent.width, width)
    y: Style.pixelAlignCenter(parent.height, height)
    width: Style.toOdd(isVertical ? (isHidden ? 0 : verticalSize) : (isHidden ? 0 : contentWidth))
    height: Style.toOdd(isVertical ? (isHidden ? 0 : verticalSize) : capsuleHeight)
    radius: Style.radiusM
    color: Style.capsuleColor
    border.color: Style.capsuleBorderColor
    border.width: Style.capsuleBorderWidth

    Behavior on width {
      NumberAnimation {
        duration: Style.animationNormal
        easing.type: Easing.InOutCubic
      }
    }
    Behavior on height {
      NumberAnimation {
        duration: Style.animationNormal
        easing.type: Easing.InOutCubic
      }
    }

    Item {
      anchors.fill: parent
      anchors.leftMargin: isVertical ? 0 : Style.marginS
      anchors.rightMargin: isVertical ? 0 : Style.marginS

      // Visualizer
      Loader {
        x: Style.pixelAlignCenter(parent.width, width)
        y: Style.pixelAlignCenter(parent.height, height)
        width: Style.toOdd(parent.width)
        height: Style.toOdd(parent.height)
        active: showVisualizer
        z: 0
        sourceComponent: {
          if (!showVisualizer)
            return null;
          if (visualizerType === "linear")
            return linearSpectrum;
          if (visualizerType === "mirrored")
            return mirroredSpectrum;
          if (visualizerType === "wave")
            return waveSpectrum;
          return null;
        }
      }

      // Horizontal layout
      RowLayout {
        anchors.fill: parent
        anchors.verticalCenter: parent.verticalCenter
        spacing: Style.marginS
        visible: !isVertical
        z: 1

        // Album art / Progress ring
        Item {
          visible: hasPlayer && (showAlbumArt || showProgressRing)
          Layout.preferredWidth: visible ? artSize : 0
          Layout.preferredHeight: visible ? artSize : 0
          Layout.alignment: Qt.AlignVCenter

          ProgressRing {
            id: progressRing
            anchors.fill: parent
            visible: showProgressRing
            progress: MediaService.trackLength > 0 ? MediaService.currentPosition / MediaService.trackLength : 0
            lineWidth: root.progressWidth
          }

          NImageRounded {
            visible: showAlbumArt && hasPlayer
            anchors.fill: parent
            anchors.margins: showProgressRing ? root.progressWidth * 2 : 0
            radius: width / 2
            imagePath: MediaService.trackArtUrl
            borderWidth: 0
            imageFillMode: Image.PreserveAspectCrop
          }
        }

        // Scrolling title
        NScrollText {
          id: titleContainer
          Layout.fillWidth: true
          Layout.alignment: Qt.AlignVCenter
          Layout.preferredHeight: capsuleHeight
          fadeRoundLeftCorners: !(showAlbumArt || showProgressRing)

          text: title

          scrollMode: {
            if (scrollingMode === "always")
              return NScrollText.ScrollMode.Always;
            if (scrollingMode === "hover")
              return NScrollText.ScrollMode.Hover;
            return NScrollText.ScrollMode.Never;
          }
          cursorShape: hasPlayer ? Qt.PointingHandCursor : Qt.ArrowCursor
          maxWidth: root.maxWidth - root.mainContentWidth
          forcedHover: mainMouseArea.containsMouse
          fadeExtent: 0.1
          fadeCornerRadius: Style.radiusM

          NText {
            color: hasPlayer ? root.textColor : Color.mOnSurfaceVariant
            pointSize: barFontSize
            elide: Text.ElideNone
          }
        }
      }

      // Vertical layout
      Item {
        id: verticalLayout
        visible: isVertical
        width: Style.toOdd(verticalSize)
        height: Style.toOdd(width)
        x: Style.pixelAlignCenter(parent.width, width)
        y: Style.pixelAlignCenter(parent.height, height)
        z: 1

        ProgressRing {
          anchors.fill: parent
          visible: showProgressRing
          progress: MediaService.trackLength > 0 ? MediaService.currentPosition / MediaService.trackLength : 0
          lineWidth: root.progressWidth
        }

        NImageRounded {
          visible: showAlbumArt && hasPlayer
          anchors.fill: parent
          anchors.margins: showProgressRing ? root.progressWidth * 2 : 0
          radius: width / 2
          imagePath: MediaService.trackArtUrl
          borderWidth: 0
          imageFillMode: Image.PreserveAspectCrop
        }
      }

      // Mouse interaction moved to root
    }
  }

  // Mouse interaction
  MouseArea {
    id: mainMouseArea
    anchors.fill: parent

    // Extend click area to screen edge if widget is at the start/end
    anchors.leftMargin: (!isVertical && section === "left" && sectionWidgetIndex === 0) ? -Style.marginS : 0
    anchors.rightMargin: (!isVertical && section === "right" && sectionWidgetIndex === sectionWidgetsCount - 1) ? -Style.marginS : 0
    anchors.topMargin: (isVertical && section === "left" && sectionWidgetIndex === 0) ? -Style.marginM : 0
    anchors.bottomMargin: (isVertical && section === "right" && sectionWidgetIndex === sectionWidgetsCount - 1) ? -Style.marginM : 0

    hoverEnabled: true
    cursorShape: Qt.PointingHandCursor
    acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton | Qt.ForwardButton | Qt.BackButton

    onClicked: mouse => {
                 TooltipService.hide();
                 if (mouse.button === Qt.LeftButton) {
                   PanelService.getPanel("mediaPlayerPanel", screen)?.toggle(container);
                 } else if (mouse.button === Qt.RightButton) {
                   PanelService.showContextMenu(contextMenu, container, screen);
                 } else if (mouse.button === Qt.MiddleButton && hasPlayer) {
                   MediaService.playPause();
                 } else if (mouse.button === Qt.ForwardButton && hasPlayer) {
                   MediaService.next();
                 } else if (mouse.button === Qt.BackButton && hasPlayer) {
                   MediaService.previous();
                 }
               }

    onEntered: {
      if (!root || !screen) {
        return;
      }
      var scrollMode = scrollingMode;
      if ((isVertical || scrollMode === "never")) {
        var panel = PanelService.getPanel("mediaPlayerPanel", screen);
        if (panel && !panel.isPanelOpen) {
          TooltipService.show(root, title, BarService.getTooltipDirection(root.screen?.name));
        }
      }
    }
    onExited: TooltipService.hide()
  }

  // Components
  Component {
    id: linearSpectrum
    NLinearSpectrum {
      width: parent.width - Style.marginS
      height: 20
      values: SpectrumService.values
      fillColor: Color.mPrimary
      opacity: 0.4
      barPosition: root.barPosition
      mirrored: Settings.data.audio.spectrumMirrored
    }
  }

  Component {
    id: mirroredSpectrum
    NMirroredSpectrum {
      width: parent.width - Style.marginS
      height: parent.height - Style.marginS
      values: SpectrumService.values
      fillColor: Color.mPrimary
      opacity: 0.4
      mirrored: Settings.data.audio.spectrumMirrored
    }
  }

  Component {
    id: waveSpectrum
    NWaveSpectrum {
      width: parent.width - Style.marginS
      height: parent.height - Style.marginS
      values: SpectrumService.values
      fillColor: Color.mPrimary
      opacity: 0.4
      mirrored: Settings.data.audio.spectrumMirrored
    }
  }

  // Progress Ring Component
  component ProgressRing: Canvas {
    property real progress: 0
    property real lineWidth: 2

    function repaint() {
      if (this.visible && this.opacity > 0)
        requestPaint();
    }

    onProgressChanged: repaint()
    Component.onCompleted: repaint()

    Connections {
      target: Color
      function onMPrimaryChanged() {
        repaint();
      }
    }

    onPaint: {
      if (width <= 0 || height <= 0)
        return;

      var ctx = getContext("2d");
      var centerX = width / 2;
      var centerY = height / 2;
      var radius = Math.min(width, height) / 2 - lineWidth;

      ctx.reset();

      // Background
      ctx.beginPath();
      ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
      ctx.lineWidth = lineWidth;
      ctx.strokeStyle = Qt.alpha(Color.mOnSurface, 0.4);
      ctx.stroke();

      // Progress
      ctx.beginPath();
      ctx.arc(centerX, centerY, radius, -Math.PI / 2, -Math.PI / 2 + progress * 2 * Math.PI);
      ctx.lineWidth = lineWidth;
      ctx.strokeStyle = Color.mPrimary;
      ctx.lineCap = "round";
      ctx.stroke();
    }
  }
}
