import QtQuick
import QtQuick.Controls
import QtQuick.Effects
import QtQuick.Layouts
import qs.Commons
import qs.Widgets
import qs.Services

NBox {
  id: root

  property string sectionName: ""
  property string sectionId: ""
  property var widgetModel: []
  property var availableWidgets: []

  signal addWidget(string widgetId, string section)
  signal removeWidget(string section, int index)
  signal reorderWidget(string section, int fromIndex, int toIndex)
  signal updateWidgetSettings(string section, int index, var settings)
  signal dragPotentialStarted
  signal dragPotentialEnded

  color: Color.mSurface
  Layout.fillWidth: true
  Layout.minimumHeight: {
    var widgetCount = widgetModel.length
    if (widgetCount === 0)
      return 140 * scaling

    var availableWidth = parent.width
    var avgWidgetWidth = 150 * scaling
    var widgetsPerRow = Math.max(1, Math.floor(availableWidth / avgWidgetWidth))
    var rows = Math.ceil(widgetCount / widgetsPerRow)

    return (50 + 20 + (rows * 48) + ((rows - 1) * Style.marginS) + 20) * scaling
  }

  // Generate widget color from name checksum
  function getWidgetColor(widget) {
    const totalSum = JSON.stringify(widget).split('').reduce((acc, character) => {
                                                               return acc + character.charCodeAt(0)
                                                             }, 0)
    switch (totalSum % 6) {
    case 0:
      return [Color.mPrimary, Color.mOnPrimary]
    case 1:
      return [Color.mSecondary, Color.mOnSecondary]
    case 2:
      return [Color.mTertiary, Color.mOnTertiary]
    case 3:
      return [Color.mError, Color.mOnError]
    case 4:
      return [Color.mOnSurface, Color.mSurface]
    case 5:
      return [Color.mOnSurfaceVariant, Color.mSurfaceVariant]
    }
  }

  ColumnLayout {
    anchors.fill: parent
    anchors.margins: Style.marginL * scaling
    spacing: Style.marginM * scaling

    RowLayout {
      Layout.fillWidth: true

      NText {
        text: sectionName + " Section"
        font.pointSize: Style.fontSizeL * scaling
        font.weight: Style.fontWeightBold
        color: Color.mOnSurface
        Layout.alignment: Qt.AlignVCenter
      }

      Item {
        Layout.fillWidth: true
      }
      NComboBox {
        id: comboBox
        model: availableWidgets
        label: ""
        description: ""
        placeholder: "Select a widget to add..."
        onSelected: key => comboBox.currentKey = key
        popupHeight: 340 * scaling

        Layout.alignment: Qt.AlignVCenter
      }

      NIconButton {
        icon: "add"

        colorBg: Color.mPrimary
        colorFg: Color.mOnPrimary
        colorBgHover: Color.mSecondary
        colorFgHover: Color.mOnSecondary
        enabled: comboBox.currentKey !== ""
        tooltipText: "Add widget to section"
        Layout.alignment: Qt.AlignVCenter
        Layout.leftMargin: Style.marginS * scaling
        onClicked: {
          if (comboBox.currentKey !== "") {
            addWidget(comboBox.currentKey, sectionId)
            comboBox.currentKey = ""
          }
        }
      }
    }

    // Drag and Drop Widget Area
    Item {
      Layout.fillWidth: true
      Layout.fillHeight: true
      Layout.minimumHeight: 65 * scaling
      clip: false // Don't clip children so ghost can move freely

      Flow {
        id: widgetFlow
        anchors.fill: parent
        spacing: Style.marginS * scaling
        flow: Flow.LeftToRight

        Repeater {
          model: widgetModel
          delegate: Rectangle {
            id: widgetItem
            required property int index
            required property var modelData

            width: widgetContent.implicitWidth + Style.marginL * scaling
            height: Style.baseWidgetSize * 1.15 * scaling
            radius: Style.radiusL * scaling
            color: root.getWidgetColor(modelData)[0]
            border.color: Color.mOutline
            border.width: Math.max(1, Style.borderS * scaling)

            // Store the widget index for drag operations
            property int widgetIndex: index
            readonly property int buttonsWidth: Math.round(20 * scaling)
            readonly property int buttonsCount: 1 + BarWidgetRegistry.widgetHasUserSettings(modelData.id)

            // Visual feedback during drag
            opacity: flowDragArea.draggedIndex === index ? 0.5 : 1.0
            scale: flowDragArea.draggedIndex === index ? 0.95 : 1.0
            z: flowDragArea.draggedIndex === index ? 1000 : 0

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

            RowLayout {
              id: widgetContent
              anchors.centerIn: parent
              spacing: Style.marginXXS * scaling

              NText {
                text: modelData.id
                font.pointSize: Style.fontSizeS * scaling
                color: root.getWidgetColor(modelData)[1]
                horizontalAlignment: Text.AlignHCenter
                elide: Text.ElideRight
                Layout.preferredWidth: 80 * scaling
              }

              RowLayout {
                spacing: 0
                Layout.preferredWidth: buttonsCount * buttonsWidth

                Loader {
                  active: BarWidgetRegistry.widgetHasUserSettings(modelData.id)
                  sourceComponent: NIconButton {
                    icon: "settings"
                    sizeRatio: 0.6
                    colorBorder: Qt.alpha(Color.mOutline, Style.opacityLight)
                    colorBg: Color.mOnSurface
                    colorFg: Color.mOnPrimary
                    colorBgHover: Qt.alpha(Color.mOnPrimary, Style.opacityLight)
                    colorFgHover: Color.mOnPrimary
                    onClicked: {
                      var component = Qt.createComponent(Qt.resolvedUrl("BarWidgetSettingsDialog.qml"))
                      function instantiateAndOpen() {
                        var dialog = component.createObject(root, {
                                                              "widgetIndex": index,
                                                              "widgetData": modelData,
                                                              "widgetId": modelData.id,
                                                              "parent": Overlay.overlay
                                                            })
                        if (dialog) {
                          dialog.open()
                        } else {
                          Logger.error("BarSectionEditor", "Failed to create settings dialog instance")
                        }
                      }
                      if (component.status === Component.Ready) {
                        instantiateAndOpen()
                      } else if (component.status === Component.Error) {
                        Logger.error("BarSectionEditor", component.errorString())
                      } else {
                        component.statusChanged.connect(function () {
                          if (component.status === Component.Ready) {
                            instantiateAndOpen()
                          } else if (component.status === Component.Error) {
                            Logger.error("BarSectionEditor", component.errorString())
                          }
                        })
                      }
                    }
                  }
                }

                NIconButton {
                  icon: "close"
                  sizeRatio: 0.6
                  colorBorder: Qt.alpha(Color.mOutline, Style.opacityLight)
                  colorBg: Color.mOnSurface
                  colorFg: Color.mOnPrimary
                  colorBgHover: Qt.alpha(Color.mOnPrimary, Style.opacityLight)
                  colorFgHover: Color.mOnPrimary
                  onClicked: {
                    removeWidget(sectionId, index)
                  }
                }
              }
            }
          }
        }
      }

      // Ghost/Clone widget for dragging
      Rectangle {
        id: dragGhost
        width: 0
        height: Style.baseWidgetSize * 1.15 * scaling
        radius: Style.radiusL * scaling
        color: Color.transparent
        border.color: Color.mOutline
        border.width: Math.max(1, Style.borderS * scaling)
        opacity: 0.7
        visible: flowDragArea.dragStarted
        z: 2000
        clip: false // Ensure ghost isn't clipped

        Text {
          id: ghostText
          anchors.centerIn: parent
          font.pointSize: Style.fontSizeS * scaling
          color: Color.mOnPrimary
        }
      }

      // Drop indicator - visual feedback for where the widget will be inserted
      Rectangle {
        id: dropIndicator
        width: 3 * scaling
        height: Style.baseWidgetSize * 1.15 * scaling
        radius: width / 2
        color: Color.mPrimary
        opacity: 0
        visible: opacity > 0
        z: 1999

        SequentialAnimation on opacity {
          id: pulseAnimation
          running: false
          loops: Animation.Infinite
          NumberAnimation {
            to: 1
            duration: 400
            easing.type: Easing.InOutQuad
          }
          NumberAnimation {
            to: 0.6
            duration: 400
            easing.type: Easing.InOutQuad
          }
        }

        Behavior on x {
          NumberAnimation {
            duration: 100
            easing.type: Easing.OutCubic
          }
        }
        Behavior on y {
          NumberAnimation {
            duration: 100
            easing.type: Easing.OutCubic
          }
        }
      }

      // MouseArea for drag and drop
      MouseArea {
        id: flowDragArea
        anchors.fill: parent
        z: -1

        acceptedButtons: Qt.LeftButton
        preventStealing: false
        propagateComposedEvents: false
        hoverEnabled: true // Always track mouse for drag operations

        property point startPos: Qt.point(0, 0)
        property bool dragStarted: false
        property bool potentialDrag: false // Track if we're in a potential drag interaction
        property int draggedIndex: -1
        property real dragThreshold: 15 * scaling
        property Item draggedWidget: null
        property int dropTargetIndex: -1
        property var draggedModelData: null

        // Drop position calculation
        function updateDropIndicator(mouseX, mouseY) {
          if (!dragStarted || draggedIndex === -1) {
            dropIndicator.opacity = 0
            pulseAnimation.running = false
            return
          }

          let bestIndex = -1
          let bestPosition = null
          let minDistance = Infinity

          // Check position relative to each widget
          for (var i = 0; i < widgetModel.length; i++) {
            if (i === draggedIndex)
              continue

            const widget = widgetFlow.children[i]
            if (!widget || widget.widgetIndex === undefined)
              continue

            // Check distance to left edge (insert before)
            const leftDist = Math.sqrt(Math.pow(mouseX - widget.x, 2) + Math.pow(mouseY - (widget.y + widget.height / 2), 2))

            // Check distance to right edge (insert after)
            const rightDist = Math.sqrt(Math.pow(mouseX - (widget.x + widget.width), 2) + Math.pow(mouseY - (widget.y + widget.height / 2), 2))

            if (leftDist < minDistance) {
              minDistance = leftDist
              bestIndex = i
              bestPosition = Qt.point(widget.x - dropIndicator.width / 2 - Style.marginXS * scaling, widget.y)
            }

            if (rightDist < minDistance) {
              minDistance = rightDist
              bestIndex = i + 1
              bestPosition = Qt.point(widget.x + widget.width + Style.marginXS * scaling - dropIndicator.width / 2, widget.y)
            }
          }

          // Check if we should insert at position 0 (very beginning)
          if (widgetModel.length > 0 && draggedIndex !== 0) {
            const firstWidget = widgetFlow.children[0]
            if (firstWidget) {
              const dist = Math.sqrt(Math.pow(mouseX, 2) + Math.pow(mouseY - firstWidget.y, 2))
              if (dist < minDistance && mouseX < firstWidget.x + firstWidget.width / 2) {
                minDistance = dist
                bestIndex = 0
                bestPosition = Qt.point(Math.max(0, firstWidget.x - dropIndicator.width - Style.marginS * scaling), firstWidget.y)
              }
            }
          }

          // Only show indicator if we're close enough and it's a different position
          if (minDistance < 80 * scaling && bestIndex !== -1) {
            // Adjust index if we're moving forward
            let adjustedIndex = bestIndex
            if (bestIndex > draggedIndex) {
              adjustedIndex = bestIndex - 1
            }

            // Don't show if it's the same position
            if (adjustedIndex === draggedIndex) {
              dropIndicator.opacity = 0
              pulseAnimation.running = false
              dropTargetIndex = -1
              return
            }

            dropTargetIndex = adjustedIndex
            if (bestPosition) {
              dropIndicator.x = bestPosition.x
              dropIndicator.y = bestPosition.y
              dropIndicator.opacity = 1
              if (!pulseAnimation.running) {
                pulseAnimation.running = true
              }
            }
          } else {
            dropIndicator.opacity = 0
            pulseAnimation.running = false
            dropTargetIndex = -1
          }
        }

        onPressed: mouse => {
                     startPos = Qt.point(mouse.x, mouse.y)
                     dragStarted = false
                     potentialDrag = false
                     draggedIndex = -1
                     draggedWidget = null
                     dropTargetIndex = -1
                     draggedModelData = null

                     // Find which widget was clicked
                     for (var i = 0; i < widgetModel.length; i++) {
                       const widget = widgetFlow.children[i]
                       if (widget && widget.widgetIndex !== undefined) {
                         if (mouse.x >= widget.x && mouse.x <= widget.x + widget.width && mouse.y >= widget.y && mouse.y <= widget.y + widget.height) {

                           const localX = mouse.x - widget.x
                           const buttonsStartX = widget.width - (widget.buttonsCount * widget.buttonsWidth)

                           if (localX < buttonsStartX) {
                             // This is a draggable area - prevent panel close immediately
                             draggedIndex = widget.widgetIndex
                             draggedWidget = widget
                             draggedModelData = widget.modelData
                             potentialDrag = true
                             preventStealing = true

                             // Signal that interaction started (prevents panel close)
                             root.dragPotentialStarted()
                             break
                           } else {
                             // This is a button area - let the click through
                             mouse.accepted = false
                             return
                           }
                         }
                       }
                     }
                   }

        onPositionChanged: mouse => {
                             if (draggedIndex !== -1 && potentialDrag) {
                               const deltaX = mouse.x - startPos.x
                               const deltaY = mouse.y - startPos.y
                               const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY)

                               if (!dragStarted && distance > dragThreshold) {
                                 dragStarted = true

                                 // Setup ghost widget
                                 if (draggedWidget) {
                                   dragGhost.width = draggedWidget.width
                                   dragGhost.color = root.getWidgetColor(draggedModelData)[0]
                                   ghostText.text = draggedModelData.id
                                 }
                               }

                               if (dragStarted) {
                                 // Move ghost widget
                                 dragGhost.x = mouse.x - dragGhost.width / 2
                                 dragGhost.y = mouse.y - dragGhost.height / 2

                                 // Update drop indicator
                                 updateDropIndicator(mouse.x, mouse.y)
                               }
                             }
                           }

        onReleased: mouse => {
                      if (dragStarted && dropTargetIndex !== -1 && dropTargetIndex !== draggedIndex) {
                        // Perform the reorder
                        reorderWidget(sectionId, draggedIndex, dropTargetIndex)
                      }

                      // Always signal end of interaction if we started one
                      if (potentialDrag) {
                        root.dragPotentialEnded()
                      }

                      // Reset everything
                      dragStarted = false
                      potentialDrag = false
                      draggedIndex = -1
                      draggedWidget = null
                      dropTargetIndex = -1
                      draggedModelData = null
                      preventStealing = false
                      dropIndicator.opacity = 0
                      pulseAnimation.running = false
                      dragGhost.width = 0
                    }

        onExited: {
          if (dragStarted) {
            // Hide drop indicator when mouse leaves, but keep ghost visible
            dropIndicator.opacity = 0
            pulseAnimation.running = false
          }
        }

        onCanceled: {
          // Handle cancel (e.g., ESC key pressed during drag)
          if (potentialDrag) {
            root.dragPotentialEnded()
          }

          // Reset everything
          dragStarted = false
          potentialDrag = false
          draggedIndex = -1
          draggedWidget = null
          dropTargetIndex = -1
          draggedModelData = null
          preventStealing = false
          dropIndicator.opacity = 0
          pulseAnimation.running = false
          dragGhost.width = 0
        }
      }
    }
  }
}
