import QtQuick
import QtQuick.Shapes
import Quickshell
import Quickshell.Wayland

import qs.Commons
import qs.Modules.MainScreen.Backgrounds
import qs.Services.UI
import qs.Widgets

// Standalone launcher window for Overlay layer mode.
// This window appears above fullscreen windows and does not attach to the bar.
Variants {
  id: launcherVariants

  model: Quickshell.screens.filter(screen => Settings.data.appLauncher.overviewLayer)

  delegate: Loader {
    id: windowLoader

    required property ShellScreen modelData

    active: PanelService.overlayLauncherOpen && PanelService.overlayLauncherScreen === modelData

    sourceComponent: PanelWindow {
      id: launcherWindow
      screen: windowLoader.modelData

      anchors {
        top: true
        bottom: true
        left: true
        right: true
      }

      color: "transparent"

      WlrLayershell.namespace: "noctalia-launcher-overlay-" + (screen?.name || "unknown")
      WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
      WlrLayershell.layer: WlrLayer.Overlay
      WlrLayershell.exclusionMode: ExclusionMode.Ignore

      BackgroundEffect.blurRegion: Settings.data.general.enableBlurBehind ? launcherBlurRegion : null
      Region {
        id: launcherBlurRegion

        Region {
          x: Math.round(launcherPanel.x)
          y: Math.round(launcherPanel.y)
          width: Math.round(launcherPanel.width)
          height: Math.round(launcherPanel.height)
          radius: Style.radiusL
          topLeftCorner: launcherPanel.topLeftCornerState
          topRightCorner: launcherPanel.topRightCornerState
          bottomLeftCorner: launcherPanel.bottomLeftCornerState
          bottomRightCorner: launcherPanel.bottomRightCornerState
        }

        Region {
          x: Math.round(previewBox.visible ? previewBox.x : 0)
          y: Math.round(previewBox.visible ? previewBox.y : 0)
          width: Math.round(previewBox.visible ? previewBox.width : 0)
          height: Math.round(previewBox.visible ? previewBox.height : 0)
          radius: Style.radiusL
        }
      }

      // Positioning logic (respects settings but doesn't attach to bar)
      readonly property string barPosition: Settings.data.bar.position
      readonly property bool barIsVertical: barPosition === "left" || barPosition === "right"
      readonly property int barThickness: Math.round(Style.barHeight + Style.marginL)

      readonly property string panelPosition: {
        var pos = Settings.data.appLauncher.position;
        if (pos === "follow_bar") {
          if (barIsVertical) {
            return "center_" + barPosition;
          } else {
            return barPosition + "_center";
          }
        }
        return pos;
      }

      // Preview panel support
      readonly property int listPanelWidth: Math.round(500 * Style.uiScaleRatio)
      readonly property int previewPanelWidth: Math.round(400 * Style.uiScaleRatio)
      readonly property bool previewActive: {
        if (!launcherCore)
          return false;
        var provider = launcherCore.activeProvider;
        if (!provider || !provider.hasPreview)
          return false;
        if (!Settings.data.appLauncher.enableClipPreview)
          return false;
        return launcherCore.selectedIndex >= 0 && launcherCore.results && !!launcherCore.results[launcherCore.selectedIndex];
      }

      // Dimmer background (click to close)
      Rectangle {
        anchors.fill: parent
        color: Qt.alpha(Color.mSurface, Settings.data.general.dimmerOpacity)

        MouseArea {
          anchors.fill: parent
          onClicked: PanelService.closeOverlayLauncher()
        }
      }

      // Shadow for launcher panel
      NDropShadow {
        source: launcherPanel
        anchors.fill: launcherPanel
        autoPaddingEnabled: true
      }

      // Launcher panel with position-based anchoring
      Item {
        id: launcherPanel
        width: Math.round(Math.max(parent.width * 0.25, launcherWindow.listPanelWidth + Style.margin2L * 2))
        height: Math.round(Math.max(parent.height * 0.5, 600 * Style.uiScaleRatio))
        clip: false

        // Entrance animation
        opacity: 0
        transformOrigin: {
          if (touchingTop && touchingLeft)
            return Item.TopLeft;
          if (touchingTop && touchingRight)
            return Item.TopRight;
          if (touchingBottom && touchingLeft)
            return Item.BottomLeft;
          if (touchingBottom && touchingRight)
            return Item.BottomRight;
          if (touchingTop)
            return Item.Top;
          if (touchingBottom)
            return Item.Bottom;
          if (touchingLeft)
            return Item.Left;
          if (touchingRight)
            return Item.Right;
          return Item.Center;
        }

        Component.onCompleted: {
          opacity = 1;
        }

        Behavior on opacity {
          NumberAnimation {
            duration: Style.animationNormal
            easing.type: Easing.OutCubic
          }
        }

        // Horizontal positioning
        anchors.horizontalCenter: (panelPosition === "center" || panelPosition.endsWith("_center")) ? parent.horizontalCenter : undefined
        anchors.left: panelPosition.endsWith("_left") ? parent.left : undefined
        anchors.right: panelPosition.endsWith("_right") ? parent.right : undefined

        // Vertical positioning
        anchors.verticalCenter: (panelPosition === "center" || panelPosition.startsWith("center_")) ? parent.verticalCenter : undefined
        anchors.top: panelPosition.startsWith("top_") ? parent.top : undefined
        anchors.bottom: panelPosition.startsWith("bottom_") ? parent.bottom : undefined

        // Margins - only add bar clearance on the bar's edge
        anchors.leftMargin: barPosition === "left" ? barThickness : 0
        anchors.rightMargin: barPosition === "right" ? barThickness : 0
        anchors.topMargin: barPosition === "top" ? barThickness : 0
        anchors.bottomMargin: barPosition === "bottom" ? barThickness : 0

        // Edge detection - based on position setting and bar location
        readonly property bool touchingLeft: panelPosition.endsWith("_left") && barPosition !== "left"
        readonly property bool touchingRight: panelPosition.endsWith("_right") && barPosition !== "right"
        readonly property bool touchingTop: panelPosition.startsWith("top_") && barPosition !== "top"
        readonly property bool touchingBottom: panelPosition.startsWith("bottom_") && barPosition !== "bottom"

        // Corner states based on edge touching
        // State 0: Normal rounded, State 1: Horizontal inversion, State 2: Vertical inversion
        readonly property int topLeftCornerState: {
          if (touchingLeft && touchingTop)
            return 0;
          if (touchingLeft)
            return 2;
          if (touchingTop)
            return 1;
          return 0;
        }
        readonly property int topRightCornerState: {
          if (touchingRight && touchingTop)
            return 0;
          if (touchingRight)
            return 2;
          if (touchingTop)
            return 1;
          return 0;
        }
        readonly property int bottomLeftCornerState: {
          if (touchingLeft && touchingBottom)
            return 0;
          if (touchingLeft)
            return 2;
          if (touchingBottom)
            return 1;
          return 0;
        }
        readonly property int bottomRightCornerState: {
          if (touchingRight && touchingBottom)
            return 0;
          if (touchingRight)
            return 2;
          if (touchingBottom)
            return 1;
          return 0;
        }

        // Background with inverted corners - extends beyond panel for inverted corners
        Shape {
          id: panelShape
          // Extend shape to allow inverted corners to render outside panel bounds
          x: -radius
          y: -radius
          width: launcherPanel.width + radius * 2
          height: launcherPanel.height + radius * 2
          visible: panelW > 0 && panelH > 0
          opacity: launcherPanel.opacity
          layer.enabled: true

          readonly property real radius: Style.radiusL

          // Panel dimensions (for path calculations)
          readonly property real panelW: launcherPanel.width
          readonly property real panelH: launcherPanel.height

          // Helper functions for corner rendering
          function getMultX(state) {
            return state === 1 ? -1 : 1;
          }
          function getMultY(state) {
            return state === 2 ? -1 : 1;
          }
          function getArcDir(multX, multY) {
            return ((multX < 0) !== (multY < 0)) ? PathArc.Counterclockwise : PathArc.Clockwise;
          }

          readonly property real tlMultX: getMultX(launcherPanel.topLeftCornerState)
          readonly property real tlMultY: getMultY(launcherPanel.topLeftCornerState)
          readonly property real trMultX: getMultX(launcherPanel.topRightCornerState)
          readonly property real trMultY: getMultY(launcherPanel.topRightCornerState)
          readonly property real blMultX: getMultX(launcherPanel.bottomLeftCornerState)
          readonly property real blMultY: getMultY(launcherPanel.bottomLeftCornerState)
          readonly property real brMultX: getMultX(launcherPanel.bottomRightCornerState)
          readonly property real brMultY: getMultY(launcherPanel.bottomRightCornerState)

          ShapePath {
            strokeWidth: -1
            fillColor: Qt.alpha(Color.mSurface, Color.adaptiveOpacity(Settings.data.ui.panelBackgroundOpacity))

            // Offset by radius to account for Shape's extended bounds
            startX: panelShape.radius + panelShape.radius * panelShape.tlMultX
            startY: panelShape.radius

            // Top edge
            PathLine {
              relativeX: panelShape.panelW - panelShape.radius * panelShape.tlMultX - panelShape.radius * panelShape.trMultX
              relativeY: 0
            }
            // Top-right corner
            PathArc {
              relativeX: panelShape.radius * panelShape.trMultX
              relativeY: panelShape.radius * panelShape.trMultY
              radiusX: panelShape.radius
              radiusY: panelShape.radius
              direction: panelShape.getArcDir(panelShape.trMultX, panelShape.trMultY)
            }
            // Right edge
            PathLine {
              relativeX: 0
              relativeY: panelShape.panelH - panelShape.radius * panelShape.trMultY - panelShape.radius * panelShape.brMultY
            }
            // Bottom-right corner
            PathArc {
              relativeX: -panelShape.radius * panelShape.brMultX
              relativeY: panelShape.radius * panelShape.brMultY
              radiusX: panelShape.radius
              radiusY: panelShape.radius
              direction: panelShape.getArcDir(panelShape.brMultX, panelShape.brMultY)
            }
            // Bottom edge
            PathLine {
              relativeX: -(panelShape.panelW - panelShape.radius * panelShape.brMultX - panelShape.radius * panelShape.blMultX)
              relativeY: 0
            }
            // Bottom-left corner
            PathArc {
              relativeX: -panelShape.radius * panelShape.blMultX
              relativeY: -panelShape.radius * panelShape.blMultY
              radiusX: panelShape.radius
              radiusY: panelShape.radius
              direction: panelShape.getArcDir(panelShape.blMultX, panelShape.blMultY)
            }
            // Left edge
            PathLine {
              relativeX: 0
              relativeY: -(panelShape.panelH - panelShape.radius * panelShape.blMultY - panelShape.radius * panelShape.tlMultY)
            }
            // Top-left corner
            PathArc {
              relativeX: panelShape.radius * panelShape.tlMultX
              relativeY: -panelShape.radius * panelShape.tlMultY
              radiusX: panelShape.radius
              radiusY: panelShape.radius
              direction: panelShape.getArcDir(panelShape.tlMultX, panelShape.tlMultY)
            }
          }
        }

        // Border
        Rectangle {
          anchors.fill: parent
          color: "transparent"
          radius: Style.radiusL
          border.color: Style.boxBorderColor
          border.width: Style.borderS
          visible: !launcherPanel.touchingLeft && !launcherPanel.touchingRight && !launcherPanel.touchingTop && !launcherPanel.touchingBottom
        }

        LauncherCore {
          id: launcherCore
          anchors.fill: parent
          screen: windowLoader.modelData
          isOpen: true
          onRequestClose: PanelService.closeOverlayLauncher()
          onRequestCloseImmediately: PanelService.closeOverlayLauncherImmediately()

          Component.onCompleted: PanelService.overlayLauncherCore = launcherCore
          Component.onDestruction: PanelService.overlayLauncherCore = null
        }
      }

      // Preview Panel - positioned as sibling of launcherPanel to avoid shadow bleed
      NDropShadow {
        source: previewBox
        anchors.fill: previewBox
        autoPaddingEnabled: true
        visible: previewBox.visible
        z: previewBox.z - 1
      }

      NBox {
        id: previewBox
        visible: launcherWindow.previewActive
        width: launcherWindow.previewPanelWidth
        height: Math.round(400 * Style.uiScaleRatio)
        forceOpaque: true
        x: {
          if (panelPosition.endsWith("_right"))
            return launcherPanel.x - launcherWindow.previewPanelWidth - Style.marginM;
          return launcherPanel.x + launcherPanel.width + Style.marginM;
        }
        y: {
          var view = launcherCore.resultsView;
          if (!view)
            return launcherPanel.y + Style.marginL;
          var row = launcherCore.isGridView ? Math.floor(launcherCore.selectedIndex / launcherCore.gridColumns) : launcherCore.selectedIndex;
          var gridCellSize = Math.floor((launcherWindow.listPanelWidth - (2 * Style.marginXS) - ((launcherCore.targetGridColumns - 1) * Style.marginS)) / launcherCore.targetGridColumns);
          var itemHeight = launcherCore.isGridView ? (gridCellSize + Style.marginXXS) : (launcherCore.entryHeight + (view.spacing || 0));
          var yPos = row * itemHeight - (view.contentY || 0);
          var mapped = view.mapToItem(launcherWindow.contentItem, 0, yPos);
          return Math.max(launcherPanel.y + Style.marginL, Math.min(mapped.y, launcherPanel.y + launcherPanel.height - previewBox.height - Style.marginL));
        }

        opacity: visible ? 1.0 : 0.0
        Behavior on opacity {
          NumberAnimation {
            duration: Style.animationFast
          }
        }
        Behavior on y {
          NumberAnimation {
            duration: Style.animationFast
            easing.type: Easing.OutCubic
          }
        }

        Loader {
          id: previewLoader
          anchors.fill: parent
          active: launcherWindow.previewActive
          source: {
            if (!active)
              return "";
            var provider = launcherCore.activeProvider;
            if (provider && provider.previewComponentPath)
              return provider.previewComponentPath;
            return "";
          }

          onLoaded: updatePreviewItem()
          onItemChanged: updatePreviewItem()

          function updatePreviewItem() {
            if (!item || launcherCore.selectedIndex < 0 || !launcherCore.results[launcherCore.selectedIndex])
              return;
            var provider = launcherCore.activeProvider;
            if (provider && provider.getPreviewData) {
              item.currentItem = provider.getPreviewData(launcherCore.results[launcherCore.selectedIndex]);
            } else {
              item.currentItem = launcherCore.results[launcherCore.selectedIndex];
            }
          }
        }
      }

      // Update preview when selection changes
      Connections {
        target: launcherCore
        function onSelectedIndexChanged() {
          if (previewLoader.item)
            previewLoader.updatePreviewItem();
        }
      }
    }
  }
}
