import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Modules.MainScreen
import qs.Modules.Panels.Settings
import qs.Services.Theming
import qs.Services.UI
import qs.Widgets

SmartPanel {
  id: root

  preferredWidth: 800 * Style.uiScaleRatio
  preferredHeight: 650 * Style.uiScaleRatio
  preferredWidthRatio: 0.5
  preferredHeightRatio: 0.5

  // Positioning
  readonly property string screenBarPosition: Settings.getBarPositionForScreen(screen?.name)
  readonly property string panelPosition: {
    if (Settings.data.wallpaper.panelPosition === "follow_bar") {
      if (screenBarPosition === "left" || screenBarPosition === "right") {
        return `center_${screenBarPosition}`;
      } else {
        return `${screenBarPosition}_center`;
      }
    } else {
      return Settings.data.wallpaper.panelPosition;
    }
  }
  panelAnchorHorizontalCenter: panelPosition === "center" || panelPosition.endsWith("_center")
  panelAnchorVerticalCenter: panelPosition === "center"
  panelAnchorLeft: panelPosition !== "center" && panelPosition.endsWith("_left")
  panelAnchorRight: panelPosition !== "center" && panelPosition.endsWith("_right")
  panelAnchorBottom: panelPosition.startsWith("bottom_")
  panelAnchorTop: panelPosition.startsWith("top_")

  // Store direct reference to content for instant access
  property var contentItem: null

  // Override keyboard handlers to enable grid navigation
  function onDownPressed() {
    if (!contentItem)
      return;
    let view = contentItem.screenRepeater.itemAt(contentItem.currentScreenIndex);
    if (view?.gridView) {
      if (!view.gridView.hasActiveFocus) {
        view.gridView.forceActiveFocus();
        if (view.gridView.currentIndex < 0 && view.gridView.model.length > 0) {
          view.gridView.currentIndex = 0;
        }
      } else {
        if (view.gridView.currentIndex < 0 && view.gridView.model.length > 0) {
          view.gridView.currentIndex = 0;
        } else {
          view.gridView.moveCurrentIndexDown();
        }
      }
    }
  }

  function onUpPressed() {
    if (!contentItem)
      return;
    let view = contentItem.screenRepeater.itemAt(contentItem.currentScreenIndex);
    if (view?.gridView?.hasActiveFocus) {
      if (view.gridView.currentIndex < 0 && view.gridView.model.length > 0) {
        view.gridView.currentIndex = 0;
      } else {
        view.gridView.moveCurrentIndexUp();
      }
    }
  }

  function onLeftPressed() {
    if (!contentItem)
      return;
    let view = contentItem.screenRepeater.itemAt(contentItem.currentScreenIndex);
    if (view?.gridView?.hasActiveFocus) {
      if (view.gridView.currentIndex < 0 && view.gridView.model.length > 0) {
        view.gridView.currentIndex = 0;
      } else {
        view.gridView.moveCurrentIndexLeft();
      }
    }
  }

  function onRightPressed() {
    if (!contentItem)
      return;
    let view = contentItem.screenRepeater.itemAt(contentItem.currentScreenIndex);
    if (view?.gridView?.hasActiveFocus) {
      if (view.gridView.currentIndex < 0 && view.gridView.model.length > 0) {
        view.gridView.currentIndex = 0;
      } else {
        view.gridView.moveCurrentIndexRight();
      }
    }
  }

  function onReturnPressed() {
    if (!contentItem)
      return;

    // Check if Wallhaven page input has focus
    if (contentItem.wallhavenView && contentItem.wallhavenView.visible && contentItem.wallhavenView.pageInput && contentItem.wallhavenView.pageInput.inputItem.activeFocus) {
      contentItem.wallhavenView.pageInput.submitPage();
      return;
    }

    let view = contentItem.screenRepeater.itemAt(contentItem.currentScreenIndex);
    if (view?.gridView?.hasActiveFocus) {
      let gridView = view.gridView;
      if (gridView.currentIndex >= 0 && gridView.currentIndex < gridView.model.count) {
        var item = gridView.model.get(gridView.currentIndex);
        view.selectItem(item.path, item.isDirectory);
      }
    }
  }

  function onEnterPressed() {
    onReturnPressed();
  }

  panelContent: Rectangle {
    id: panelContent

    property alias wallhavenView: wallhavenView
    property int currentScreenIndex: {
      if (screen !== null) {
        for (var i = 0; i < Quickshell.screens.length; i++) {
          if (Quickshell.screens[i].name == screen.name) {
            return i;
          }
        }
      }
      return 0;
    }
    property var currentScreen: Quickshell.screens[currentScreenIndex]
    property string filterText: ""
    property int appearanceTabIndex: 0
    readonly property bool headerScreensStripAvailable: !Settings.data.wallpaper.setWallpaperOnAllMonitors || Settings.data.wallpaper.enableMultiMonitorDirectories
    readonly property bool headerDevicesButtonVisible: Quickshell.screens.length > 1 || Settings.data.wallpaper.enableMultiMonitorDirectories
    property alias screenRepeater: screenRepeater

    Component.onCompleted: {
      root.contentItem = panelContent;
    }

    // Function to update Wallhaven resolution filter
    function updateWallhavenResolution() {
      if (typeof WallhavenService === "undefined") {
        return;
      }

      var width = Settings.data.wallpaper.wallhavenResolutionWidth || "";
      var height = Settings.data.wallpaper.wallhavenResolutionHeight || "";
      var mode = Settings.data.wallpaper.wallhavenResolutionMode || "atleast";

      if (width && height) {
        var resolution = width + "x" + height;
        if (mode === "atleast") {
          WallhavenService.minResolution = resolution;
          WallhavenService.resolutions = "";
        } else {
          WallhavenService.minResolution = "";
          WallhavenService.resolutions = resolution;
        }
      } else {
        WallhavenService.minResolution = "";
        WallhavenService.resolutions = "";
      }

      // Trigger new search with updated resolution
      if (Settings.data.wallpaper.useWallhaven) {
        if (wallhavenView) {
          wallhavenView.loading = true;
        }
        WallhavenService.search(Settings.data.wallpaper.wallhavenQuery || "", 1);
      }
    }

    color: "transparent"

    // Wallhaven settings popup
    Loader {
      id: wallhavenSettingsPopup
      source: "WallhavenSettingsPopup.qml"
      onLoaded: {
        if (item) {
          item.screen = screen;
        }
      }
    }

    // Solid color picker dialog
    NColorPickerDialog {
      id: solidColorPicker
      screen: root.screen
      selectedColor: Settings.data.wallpaper.solidColor
      onColorSelected: color => WallpaperService.setSolidColor(color.toString())
    }

    // Focus management
    Connections {
      target: root
      function onOpened() {
        // Ensure contentItem is set
        if (!root.contentItem) {
          root.contentItem = panelContent;
        }
        // Reset grid view selections
        for (var i = 0; i < screenRepeater.count; i++) {
          let item = screenRepeater.itemAt(i);
          if (item && item.gridView) {
            item.gridView.currentIndex = -1;
          }
        }
        if (wallhavenView && wallhavenView.gridView) {
          wallhavenView.gridView.currentIndex = -1;
        }
        panelContent.appearanceTabIndex = Settings.data.colorSchemes.darkMode ? 1 : 0;
        WallpaperService.wallpaperSelectionAppearance = panelContent.appearanceTabIndex === 1 ? "dark" : "light";
        // Give initial focus to search input
        Qt.callLater(() => {
                       if (searchInput.inputItem) {
                         searchInput.inputItem.forceActiveFocus();
                       }
                     });
      }
    }

    // Debounce timer for search
    Timer {
      id: searchDebounceTimer
      interval: 150
      onTriggered: {
        panelContent.filterText = searchInput.text;
        // Trigger update on all screen views
        for (var i = 0; i < screenRepeater.count; i++) {
          let item = screenRepeater.itemAt(i);
          if (item && item.updateFiltered) {
            item.updateFiltered();
          }
        }
      }
    }

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

      // Debounce timer for Wallhaven search
      Timer {
        id: wallhavenSearchDebounceTimer
        interval: 500
        onTriggered: {
          Settings.data.wallpaper.wallhavenQuery = searchInput.text;
          if (typeof WallhavenService !== "undefined") {
            wallhavenView.loading = true;
            WallhavenService.search(searchInput.text, 1);
          }
        }
      }

      // Header
      NBox {
        Layout.fillWidth: true
        Layout.preferredHeight: headerColumn.implicitHeight + Style.margin2L
        color: Color.mSurfaceVariant

        ColumnLayout {
          id: headerColumn
          anchors.fill: parent
          anchors.margins: Style.marginL
          spacing: Style.marginM

          RowLayout {
            Layout.fillWidth: true
            spacing: Style.marginM

            NIcon {
              icon: "settings-wallpaper-selector"
              pointSize: Style.fontSizeXXL
              color: Color.mPrimary
            }

            NText {
              text: I18n.tr("wallpaper.panel.title")
              pointSize: Style.fontSizeL
              font.weight: Style.fontWeightBold
              color: Color.mOnSurface
              Layout.fillWidth: true
            }

            NIconButton {
              visible: Settings.data.wallpaper.enabled
              icon: "sun"
              tooltipText: Settings.data.wallpaper.linkLightAndDarkWallpapers ? I18n.tr("wallpaper.panel.header-sun-linked-tooltip") : I18n.tr("wallpaper.panel.header-sun-separate-tooltip")
              baseSize: Style.baseWidgetSize * 0.8
              colorBg: !Settings.data.wallpaper.linkLightAndDarkWallpapers ? Color.mPrimary : Color.smartAlpha(Color.mSurfaceVariant)
              colorFg: !Settings.data.wallpaper.linkLightAndDarkWallpapers ? Color.mOnPrimary : Color.mPrimary
              onClicked: Settings.data.wallpaper.linkLightAndDarkWallpapers = !Settings.data.wallpaper.linkLightAndDarkWallpapers
            }

            NIconButton {
              visible: Settings.data.wallpaper.enabled && panelContent.headerDevicesButtonVisible
              icon: "devices"
              tooltipText: Settings.data.wallpaper.setWallpaperOnAllMonitors ? I18n.tr("wallpaper.panel.header-devices-apply-all-tooltip") : I18n.tr("wallpaper.panel.header-devices-per-monitor-tooltip")
              baseSize: Style.baseWidgetSize * 0.8
              colorBg: !Settings.data.wallpaper.setWallpaperOnAllMonitors ? Color.mPrimary : Color.smartAlpha(Color.mSurfaceVariant)
              colorFg: !Settings.data.wallpaper.setWallpaperOnAllMonitors ? Color.mOnPrimary : Color.mPrimary
              onClicked: Settings.data.wallpaper.setWallpaperOnAllMonitors = !Settings.data.wallpaper.setWallpaperOnAllMonitors
            }

            NIconButton {
              icon: "palette"
              tooltipText: I18n.tr("wallpaper.panel.solid-color-tooltip")
              baseSize: Style.baseWidgetSize * 0.8
              colorBg: Settings.data.wallpaper.useSolidColor ? Color.mPrimary : Color.mSurfaceVariant
              colorFg: Settings.data.wallpaper.useSolidColor ? Color.mOnPrimary : Color.mPrimary
              onClicked: solidColorPicker.open()
            }

            NIconButton {
              icon: "settings"
              tooltipText: I18n.tr("panels.wallpaper.settings-title")
              baseSize: Style.baseWidgetSize * 0.8
              onClicked: {
                var settingsPanel = PanelService.getPanel("settingsPanel", screen);
                settingsPanel.requestedTab = SettingsPanel.Tab.Wallpaper;
                settingsPanel.open();
              }
            }

            NIconButton {
              icon: "close"
              tooltipText: I18n.tr("common.close")
              baseSize: Style.baseWidgetSize * 0.8
              onClicked: root.close()
            }
          }

          NDivider {
            Layout.fillWidth: true
          }

          NTabBar {
            id: appearanceTabBar
            visible: Settings.data.wallpaper.enabled && !Settings.data.wallpaper.linkLightAndDarkWallpapers
            Layout.fillWidth: true
            currentIndex: panelContent.appearanceTabIndex
            spacing: Style.marginM
            distributeEvenly: true

            onCurrentIndexChanged: {
              if (currentIndex < 0) {
                return;
              }
              panelContent.appearanceTabIndex = currentIndex;
              WallpaperService.wallpaperSelectionAppearance = currentIndex === 1 ? "dark" : "light";
              Settings.data.colorSchemes.darkMode = currentIndex === 1;
            }

            NTabButton {
              text: I18n.tr("wallpaper.panel.appearance-light-tab")
              tabIndex: 0
              checked: appearanceTabBar.currentIndex === 0
            }
            NTabButton {
              text: I18n.tr("wallpaper.panel.appearance-dark-tab")
              tabIndex: 1
              checked: appearanceTabBar.currentIndex === 1
            }
          }

          NTabBar {
            id: screenTabBar
            visible: panelContent.headerScreensStripAvailable
            Layout.fillWidth: true
            currentIndex: currentScreenIndex
            onCurrentIndexChanged: currentScreenIndex = currentIndex
            spacing: Style.marginM
            distributeEvenly: true

            Repeater {
              model: Quickshell.screens
              NTabButton {
                required property var modelData
                required property int index
                text: modelData.name || `Screen ${index + 1}`
                tabIndex: index
                checked: {
                  screenTabBar.currentIndex === index;
                }
              }
            }
          }

          // Unified search input and source
          RowLayout {
            Layout.fillWidth: true
            spacing: Style.marginM

            NTextInput {
              id: searchInput
              placeholderText: Settings.data.wallpaper.useWallhaven ? I18n.tr("placeholders.search-wallhaven") : I18n.tr("placeholders.search-wallpapers")
              fontSize: Style.fontSizeM
              Layout.fillWidth: true

              property bool initializing: true
              Component.onCompleted: {
                // Initialize text based on current mode
                if (Settings.data.wallpaper.useWallhaven) {
                  searchInput.text = Settings.data.wallpaper.wallhavenQuery || "";
                } else {
                  searchInput.text = panelContent.filterText || "";
                }
                // Give focus to search input
                if (searchInput.inputItem && searchInput.inputItem.visible) {
                  searchInput.inputItem.forceActiveFocus();
                }
                // Mark initialization as complete after a short delay
                Qt.callLater(function () {
                  searchInput.initializing = false;
                });
              }

              Connections {
                target: Settings.data.wallpaper
                function onUseWallhavenChanged() {
                  // Update text when mode changes
                  if (Settings.data.wallpaper.useWallhaven) {
                    searchInput.text = Settings.data.wallpaper.wallhavenQuery || "";
                  } else {
                    searchInput.text = panelContent.filterText || "";
                  }
                }
              }

              onTextChanged: {
                // Don't trigger search during initialization - Component.onCompleted will handle initial search
                if (initializing) {
                  return;
                }
                if (Settings.data.wallpaper.useWallhaven) {
                  wallhavenSearchDebounceTimer.restart();
                } else {
                  searchDebounceTimer.restart();
                }
              }

              onEditingFinished: {
                if (Settings.data.wallpaper.useWallhaven) {
                  wallhavenSearchDebounceTimer.stop();
                  // Only search if the query actually changed
                  if (typeof WallhavenService !== "undefined" && text !== WallhavenService.currentQuery) {
                    Settings.data.wallpaper.wallhavenQuery = text;
                    wallhavenView.loading = true;
                    WallhavenService.search(text, 1);
                  }
                }
              }

              Keys.onPressed: event => {
                                if (Keybinds.checkKey(event, 'down', Settings)) {
                                  if (Settings.data.wallpaper.useWallhaven) {
                                    if (wallhavenView && wallhavenView.gridView) {
                                      wallhavenView.gridView.forceActiveFocus();
                                    }
                                  } else {
                                    let currentView = screenRepeater.itemAt(currentScreenIndex);
                                    if (currentView && currentView.gridView) {
                                      currentView.gridView.forceActiveFocus();
                                    }
                                  }
                                  event.accepted = true;
                                }
                              }
            }

            NIconButton {
              icon: "color-swatch"
              tooltipText: Settings.data.colorSchemes.useWallpaperColors ? I18n.tr("wallpaper.panel.color-extraction-enabled") : I18n.tr("wallpaper.panel.color-extraction-disabled")
              baseSize: Style.baseWidgetSize * 0.8
              onClicked: {
                Settings.data.colorSchemes.useWallpaperColors = !Settings.data.colorSchemes.useWallpaperColors;
                if (Settings.data.colorSchemes.useWallpaperColors) {
                  AppThemeService.generate();
                } else {
                  ColorSchemeService.setPredefinedScheme(Settings.data.colorSchemes.predefinedScheme);
                }
              }
            }

            NComboBox {
              id: colorSchemeComboBox
              Layout.fillWidth: false
              Layout.minimumWidth: 200
              minimumWidth: 200

              property bool _initialized: false
              property bool _userChanging: false
              Component.onCompleted: Qt.callLater(() => {
                                                    _initialized = true;
                                                  })

              model: Settings.data.colorSchemes.useWallpaperColors ? TemplateProcessor.schemeTypes : ColorSchemeService.schemes.map(s => ({
                                                                                                                                            "key": ColorSchemeService.getBasename(s),
                                                                                                                                            "name": ColorSchemeService.getBasename(s)
                                                                                                                                          }))
              currentKey: Settings.data.colorSchemes.useWallpaperColors ? Settings.data.colorSchemes.generationMethod : Settings.data.colorSchemes.predefinedScheme
              onCurrentKeyChanged: {
                if (!_initialized)
                  return;
                if (_userChanging) {
                  _userChanging = false;
                  return;
                }
                schemeGlowAnimation.restart();
              }
              onSelected: key => {
                            _userChanging = true;
                            if (Settings.data.colorSchemes.useWallpaperColors) {
                              Settings.data.colorSchemes.generationMethod = key;
                              AppThemeService.generate();
                            } else {
                              ColorSchemeService.setPredefinedScheme(key);
                            }
                            Qt.callLater(() => {
                                           _userChanging = false;
                                         });
                          }

              SequentialAnimation {
                id: schemeGlowAnimation
                NumberAnimation {
                  target: colorSchemeComboBox
                  property: "opacity"
                  to: 0.3
                  duration: Style.animationSlow
                  easing.type: Easing.OutCubic
                }
                NumberAnimation {
                  target: colorSchemeComboBox
                  property: "opacity"
                  to: 1.0
                  duration: Style.animationSlow
                  easing.type: Easing.InCubic
                }
              }
            }

            NComboBox {
              id: sourceComboBox
              Layout.fillWidth: false

              model: [
                {
                  "key": "local",
                  "name": I18n.tr("common.local")
                },
                {
                  "key": "wallhaven",
                  "name": I18n.tr("wallpaper.panel.source-wallhaven")
                }
              ]
              currentKey: Settings.data.wallpaper.useWallhaven ? "wallhaven" : "local"
              property bool skipNextSelected: false
              Component.onCompleted: {
                // Skip the first onSelected if it fires during initialization
                skipNextSelected = true;
                Qt.callLater(function () {
                  skipNextSelected = false;
                });
              }
              onSelected: key => {
                            if (skipNextSelected) {
                              return;
                            }
                            var useWallhaven = (key === "wallhaven");
                            Settings.data.wallpaper.useWallhaven = useWallhaven;
                            // Update search input text based on mode
                            if (useWallhaven) {
                              searchInput.text = Settings.data.wallpaper.wallhavenQuery || "";
                            } else {
                              searchInput.text = panelContent.filterText || "";
                            }
                            if (useWallhaven && typeof WallhavenService !== "undefined") {
                              // Update service properties when switching to Wallhaven
                              // Don't search here - Component.onCompleted will handle it when the component is created
                              // This prevents duplicate searches
                              WallhavenService.categories = Settings.data.wallpaper.wallhavenCategories;
                              WallhavenService.purity = Settings.data.wallpaper.wallhavenPurity;
                              WallhavenService.sorting = Settings.data.wallpaper.wallhavenSorting;
                              WallhavenService.order = Settings.data.wallpaper.wallhavenOrder;

                              // Update resolution settings
                              panelContent.updateWallhavenResolution();

                              // If the view is already initialized, trigger a new search when switching to it
                              // Preserve current page when switching back to Wallhaven source
                              if (wallhavenView && wallhavenView.initialized && !WallhavenService.fetching) {
                                wallhavenView.loading = true;
                                WallhavenService.search(Settings.data.wallpaper.wallhavenQuery || "", WallhavenService.currentPage);
                              }
                            }
                          }
            }

            // Settings button (only visible for Wallhaven)
            NIconButton {
              id: wallhavenSettingsButton
              icon: "settings"
              tooltipText: I18n.tr("wallpaper.panel.wallhaven-settings-title")
              baseSize: Style.baseWidgetSize * 0.8
              visible: Settings.data.wallpaper.useWallhaven
              onClicked: {
                if (searchInput.inputItem) {
                  searchInput.inputItem.focus = false;
                }
                if (wallhavenSettingsPopup.item) {
                  wallhavenSettingsPopup.item.showAt(wallhavenSettingsButton);
                }
              }
            }
          }
        }
      }

      // Content stack: Wallhaven or Local
      NBox {
        Layout.fillWidth: true
        Layout.fillHeight: true
        color: Color.mSurfaceVariant

        StackLayout {
          id: contentStack
          anchors.fill: parent
          anchors.margins: Style.marginL

          currentIndex: Settings.data.wallpaper.useWallhaven ? 1 : 0

          // Local wallpapers
          StackLayout {
            id: screenStack
            currentIndex: currentScreenIndex

            Repeater {
              id: screenRepeater
              model: Quickshell.screens
              delegate: WallpaperScreenView {
                targetScreen: modelData
              }
            }
          }

          // Wallhaven wallpapers
          WallhavenView {
            id: wallhavenView
          }
        }
      }
    }
  }

  // Component for each screen's wallpaper view
  component WallpaperScreenView: Item {
    id: wallpaperScreenView
    property var targetScreen
    property alias gridView: wallpaperGridView

    // Local reactive state for this screen
    property list<string> wallpapersList: []
    property string currentWallpaper: ""
    property var filteredItems: [] // Combined list of { path, name, isDirectory }
    property var wallpapersWithNames: [] // Cached basenames for files
    property var directoriesList: [] // List of directories in browse mode

    // ListModel for the grid — enables animated reordering via move()
    ListModel {
      id: wallpaperModel
    }

    // Browse mode properties
    property string currentBrowsePath: WallpaperService.getCurrentBrowsePath(targetScreen?.name ?? "")
    property bool isBrowseMode: Settings.data.wallpaper.viewMode === "browse"
    property int _browseScanGeneration: 0

    // Favorited paths (any light/dark) first, then the rest
    function sortFavoritesToTop(items) {
      var favs = [];
      var rest = [];
      for (var i = 0; i < items.length; i++) {
        var it = items[i];
        if (!it.isDirectory && WallpaperService.isFavorite(it.path)) {
          favs.push(it);
        } else {
          rest.push(it);
        }
      }
      return favs.concat(rest);
    }

    // Rebuild filteredItems and sync to wallpaperModel (full replacement, no animation).
    // When skipSync is true the caller will animate the model itself.
    function updateFiltered(skipSync) {
      var combinedItems = [];

      // In browse mode, add directories first
      if (isBrowseMode) {
        for (var i = 0; i < directoriesList.length; i++) {
          var dirPath = directoriesList[i];
          combinedItems.push({
                               "path": dirPath,
                               "name": dirPath.split('/').pop(),
                               "isDirectory": true
                             });
        }
      }

      // Add files
      for (var i = 0; i < wallpapersList.length; i++) {
        combinedItems.push({
                             "path": wallpapersList[i],
                             "name": wallpapersList[i].split('/').pop(),
                             "isDirectory": false
                           });
      }

      combinedItems = sortFavoritesToTop(combinedItems);

      // Apply filter if text is present
      if (!panelContent.filterText || panelContent.filterText.trim().length === 0) {
        filteredItems = combinedItems;
        if (!skipSync)
          syncModel();
        return;
      }

      const results = FuzzySort.go(panelContent.filterText.trim(), combinedItems, {
                                     "key": 'name',
                                     "limit": 200
                                   });
      var filtered = results.map(function (r) {
        return r.obj;
      });
      filteredItems = sortFavoritesToTop(filtered);
      if (!skipSync)
        syncModel();
    }

    // Copy filteredItems into the ListModel (full rebuild, no animation).
    function syncModel() {
      wallpaperModel.clear();
      for (var i = 0; i < filteredItems.length; i++) {
        wallpaperModel.append(filteredItems[i]);
      }
      wallpaperGridView.currentIndex = -1;
      wallpaperGridView.positionViewAtBeginning();
    }

    // Animate a single item moving to its new position after a favorite toggle.
    function handleFavoriteMove(path) {
      // Find where the item currently sits in the model
      var fromIndex = -1;
      for (var i = 0; i < wallpaperModel.count; i++) {
        if (wallpaperModel.get(i).path === path) {
          fromIndex = i;
          break;
        }
      }
      if (fromIndex === -1)
        return;

      // Find where it should be in the freshly-computed filteredItems
      var toIndex = -1;
      for (var j = 0; j < filteredItems.length; j++) {
        if (filteredItems[j].path === path) {
          toIndex = j;
          break;
        }
      }
      if (toIndex === -1 || fromIndex === toIndex)
        return;

      wallpaperGridView.animateMovement = true;
      wallpaperModel.move(fromIndex, toIndex, 1);
      animateMovementResetTimer.restart();
    }

    // Turn off move animations shortly after the move completes so that
    // non-favorite model rebuilds (sort, filter, navigation) don't animate.
    Timer {
      id: animateMovementResetTimer
      readonly property int settleDelay: 50
      interval: Style.animationNormal + settleDelay
      onTriggered: {
        wallpaperGridView.animateMovement = false;
        reconcileModel();
      }
    }

    // Reorder wallpaperModel to match filteredItems using in-place moves.
    // Avoids clear+rebuild which would destroy delegates and flash thumbnails.
    function reconcileModel() {
      for (var i = 0; i < filteredItems.length; i++) {
        var currentPos = -1;
        for (var j = i; j < wallpaperModel.count; j++) {
          if (wallpaperModel.get(j).path === filteredItems[i].path) {
            currentPos = j;
            break;
          }
        }
        if (currentPos !== -1 && currentPos !== i) {
          wallpaperModel.move(currentPos, i, 1);
        }
      }
    }

    Component.onCompleted: {
      refreshWallpaperScreenData();
    }

    Connections {
      target: WallpaperService
      function onWallpaperChanged(screenName, path) {
        if (targetScreen !== null && screenName === targetScreen.name) {
          currentWallpaper = WallpaperService.getWallpaperPathForSlot(targetScreen.name, WallpaperService.wallpaperSelectionAppearance);
        }
      }
      function onWallpaperSelectionAppearanceChanged() {
        if (targetScreen !== null) {
          currentWallpaper = WallpaperService.getWallpaperPathForSlot(targetScreen.name, WallpaperService.wallpaperSelectionAppearance);
          updateFiltered(false);
        }
      }
      function onWallpaperDirectoryChanged(screenName, directory) {
        if (targetScreen !== null && screenName === targetScreen.name) {
          // Reset browse path when root directory changes
          if (isBrowseMode) {
            WallpaperService.navigateToRoot(targetScreen.name);
          }
          refreshWallpaperScreenData();
        }
      }
      function onWallpaperListChanged(screenName, count) {
        if (targetScreen !== null && screenName === targetScreen.name) {
          refreshWallpaperScreenData();
        }
      }
      function onBrowsePathChanged(screenName, path) {
        if (targetScreen !== null && screenName === targetScreen.name) {
          currentBrowsePath = path;
          refreshWallpaperScreenData();
        }
      }
      function onFavoritesChanged(path) {
        updateFiltered(true);   // recompute filteredItems but skip full model rebuild
        handleFavoriteMove(path); // animate the item to its new position
      }
    }

    function refreshWallpaperScreenData() {
      if (targetScreen === null) {
        return;
      }

      currentWallpaper = WallpaperService.getWallpaperPathForSlot(targetScreen.name, WallpaperService.wallpaperSelectionAppearance);

      if (isBrowseMode) {
        // In browse mode, scan current directory for both files and directories
        var browsePath = WallpaperService.getCurrentBrowsePath(targetScreen.name);
        currentBrowsePath = browsePath;

        // Bump generation so stale scan callbacks from rapid navigation are ignored
        var gen = ++_browseScanGeneration;
        WallpaperService.scanDirectoryWithDirs(targetScreen.name, browsePath, function (result) {
          if (gen !== _browseScanGeneration)
            return; // Stale callback from a superseded navigation
          wallpapersList = result.files;
          directoriesList = result.directories;
          Logger.d("WallpaperPanel", "Browse mode: Got", wallpapersList.length, "files and", directoriesList.length, "directories for screen", targetScreen.name);
          updateFiltered();
        });
      } else {
        // Normal mode: just use the wallpaper list from service
        wallpapersList = WallpaperService.getWallpapersList(targetScreen.name);
        directoriesList = [];
        Logger.d("WallpaperPanel", "Got", wallpapersList.length, "wallpapers for screen", targetScreen.name);
        updateFiltered();
      }
    }

    function selectItem(path, isDirectory) {
      if (isDirectory) {
        WallpaperService.setBrowsePath(targetScreen.name, path);
      } else {
        var screen = Settings.data.wallpaper.setWallpaperOnAllMonitors ? undefined : targetScreen.name;
        WallpaperService.changeWallpaper(path, screen, WallpaperService.wallpaperSelectionAppearance);
        WallpaperService.applyFavoriteTheme(path, screen, WallpaperService.wallpaperSelectionAppearance);
      }
    }

    // Helper function to cycle view modes
    function cycleViewMode() {
      var mode = Settings.data.wallpaper.viewMode;
      if (mode === "single") {
        Settings.data.wallpaper.viewMode = "recursive";
      } else if (mode === "recursive") {
        Settings.data.wallpaper.viewMode = "browse";
      } else {
        Settings.data.wallpaper.viewMode = "single";
      }
    }

    // Helper function to get icon for current view mode
    function getViewModeIcon() {
      var mode = Settings.data.wallpaper.viewMode;
      if (mode === "single")
        return "folder";
      if (mode === "recursive")
        return "folders";
      return "folder-open";
    }

    // Helper function to get tooltip for current view mode
    function getViewModeTooltip() {
      var mode = Settings.data.wallpaper.viewMode;
      var modeName;
      if (mode === "single")
        modeName = I18n.tr("panels.wallpaper.view-mode-single");
      else if (mode === "recursive")
        modeName = I18n.tr("panels.wallpaper.view-mode-recursive");
      else
        modeName = I18n.tr("panels.wallpaper.view-mode-browse");
      return I18n.tr("panels.wallpaper.view-mode-cycle-tooltip").replace("{mode}", modeName);
    }

    ColumnLayout {
      anchors.fill: parent
      spacing: Style.marginM

      // Combined toolbar: navigation (left) + actions (right)
      RowLayout {
        Layout.fillWidth: true
        spacing: Style.marginS

        // Left side: navigation (back, home, path)
        NIconButton {
          icon: "arrow-left"
          tooltipText: I18n.tr("wallpaper.browse.go-up")
          enabled: isBrowseMode && currentBrowsePath !== WallpaperService.getMonitorDirectory(targetScreen?.name ?? "")
          onClicked: WallpaperService.navigateUp(targetScreen?.name ?? "")
          baseSize: Style.baseWidgetSize * 0.8
        }

        NIconButton {
          icon: "home"
          tooltipText: I18n.tr("wallpaper.browse.go-root")
          enabled: isBrowseMode && currentBrowsePath !== WallpaperService.getMonitorDirectory(targetScreen?.name ?? "")
          onClicked: WallpaperService.navigateToRoot(targetScreen?.name ?? "")
          baseSize: Style.baseWidgetSize * 0.8
        }

        NScrollText {
          text: isBrowseMode ? currentBrowsePath : WallpaperService.getMonitorDirectory(targetScreen?.name ?? "")
          Layout.fillWidth: true
          scrollMode: NScrollText.ScrollMode.Hover
          fadeCornerRadius: Style.radiusM

          NText {
            text: isBrowseMode ? currentBrowsePath : WallpaperService.getMonitorDirectory(targetScreen?.name ?? "")
            pointSize: Style.fontSizeS
            color: Color.mOnSurfaceVariant
          }
        }

        // Right side: actions (view mode, hide filenames, refresh)
        NIconButton {
          property string sortOrder: Settings.data.wallpaper.sortOrder || "name"
          icon: {
            if (sortOrder === "date_desc")
              return "clock";
            if (sortOrder === "date_asc")
              return "history";
            if (sortOrder === "name_desc")
              return "sort-descending";
            if (sortOrder === "random")
              return "arrows-shuffle";
            return "sort-ascending";
          }
          tooltipText: {
            if (sortOrder === "date_desc")
              return I18n.tr("wallpaper.panel.sort-date-desc");
            if (sortOrder === "date_asc")
              return I18n.tr("wallpaper.panel.sort-date-asc");
            if (sortOrder === "name_desc")
              return I18n.tr("wallpaper.panel.sort-name-desc");
            if (sortOrder === "random")
              return I18n.tr("wallpaper.panel.sort-random");
            return I18n.tr("wallpaper.panel.sort-name-asc");
          }
          baseSize: Style.baseWidgetSize * 0.8
          onClicked: {
            var next = "name";
            if (sortOrder === "name")
              next = "date_desc";
            else if (sortOrder === "date_desc")
              next = "name"; // Toggle simpler: Name -> Newest -> Name
            // Expanded cycle: Name -> Newest -> Oldest -> Z-A -> Random -> Name
            // User just asked for "newest first", so let's make it easy to reach.
            // Let's do: Name (A-Z) -> Newest -> Oldest -> Name (Z-A) -> ...

            if (sortOrder === "name")
              next = "date_desc";
            else if (sortOrder === "date_desc")
              next = "date_asc";
            else if (sortOrder === "date_asc")
              next = "name_desc";
            else if (sortOrder === "name_desc")
              next = "random";
            else
              next = "name";

            Settings.data.wallpaper.sortOrder = next;
          }
        }

        NIconButton {
          icon: getViewModeIcon()
          tooltipText: getViewModeTooltip()
          baseSize: Style.baseWidgetSize * 0.8
          onClicked: cycleViewMode()
        }

        NIconButton {
          icon: Settings.data.wallpaper.hideWallpaperFilenames ? "id-off" : "id"
          tooltipText: Settings.data.wallpaper.hideWallpaperFilenames ? I18n.tr("panels.wallpaper.settings-hide-wallpaper-filenames-tooltip-show") : I18n.tr("panels.wallpaper.settings-hide-wallpaper-filenames-tooltip-hide")
          baseSize: Style.baseWidgetSize * 0.8
          onClicked: Settings.data.wallpaper.hideWallpaperFilenames = !Settings.data.wallpaper.hideWallpaperFilenames
        }

        NIconButton {
          icon: Settings.data.wallpaper.showHiddenFiles ? "eye" : "eye-closed"
          tooltipText: Settings.data.wallpaper.showHiddenFiles ? I18n.tr("panels.wallpaper.settings-show-hidden-files-tooltip-hide") : I18n.tr("panels.wallpaper.settings-show-hidden-files-tooltip-show")
          baseSize: Style.baseWidgetSize * 0.8
          onClicked: Settings.data.wallpaper.showHiddenFiles = !Settings.data.wallpaper.showHiddenFiles
        }

        NIconButton {
          icon: "refresh"
          tooltipText: I18n.tr("tooltips.refresh-wallpaper-list")
          baseSize: Style.baseWidgetSize * 0.8
          onClicked: {
            if (isBrowseMode) {
              refreshWallpaperScreenData();
            } else {
              WallpaperService.refreshWallpapersList();
            }
          }
        }
      }

      NGridView {
        id: wallpaperGridView

        Layout.fillWidth: true
        Layout.fillHeight: true

        visible: !WallpaperService.scanning
        interactive: true
        keyNavigationEnabled: true
        keyNavigationWraps: false
        highlightFollowsCurrentItem: false
        currentIndex: -1

        model: wallpaperModel

        Component.onCompleted: {
          positionViewAtBeginning();
        }

        property int columns: (screen.width > 1920) ? 5 : 4
        property int itemSize: cellWidth

        cellWidth: Math.floor((availableWidth - leftMargin - rightMargin) / columns)
        cellHeight: Math.floor(itemSize * 0.7) + Style.marginXS + Style.fontSizeXS + Style.marginM

        leftMargin: Style.marginS
        rightMargin: Style.marginS
        topMargin: Style.marginS
        bottomMargin: Style.marginS

        onCurrentIndexChanged: {
          if (currentIndex >= 0) {
            positionViewAtIndex(currentIndex, GridView.Contain);
          }
        }

        onKeyPressed: event => {
                        if (Keybinds.checkKey(event, 'enter', Settings)) {
                          if (currentIndex >= 0 && currentIndex < filteredItems.length) {
                            selectItem(filteredItems[currentIndex]);
                          }
                          event.accepted = true;
                        }
                      }

        delegate: Item {
          id: wallpaperItemWrapper
          width: wallpaperGridView.cellWidth
          height: wallpaperGridView.cellHeight

          ColumnLayout {
            id: wallpaperItem
            anchors.fill: parent
            anchors.margins: Style.marginXS

            property string wallpaperPath: model.path ?? ""
            property bool isDirectory: model.isDirectory ?? false
            property bool isSelected: !isDirectory && (wallpaperPath === currentWallpaper)
            property bool isFavorited: {
              WallpaperService.favoritesRevision;
              return !isDirectory && WallpaperService.isFavorite(wallpaperPath);
            }
            property string filename: model.name ?? wallpaperPath.split('/').pop()
            property string cachedPath: ""

            spacing: Style.marginXS

            Component.onCompleted: {
              if (!isDirectory && ImageCacheService.initialized) {
                ImageCacheService.getThumbnail(wallpaperPath, function (path, success) {
                  if (wallpaperItem)
                    wallpaperItem.cachedPath = success ? path : wallpaperPath;
                });
              } else if (!isDirectory) {
                cachedPath = wallpaperPath;
              }
            }

            Item {
              id: imageContainer
              Layout.fillWidth: true
              Layout.fillHeight: true

              property real imageHeight: Math.round(wallpaperGridView.itemSize * 0.67)

              // Directory display
              Rectangle {
                anchors.left: parent.left
                anchors.right: parent.right
                anchors.top: parent.top
                height: imageContainer.imageHeight
                color: Color.mSurfaceVariant
                radius: Style.radiusM
                visible: wallpaperItem.isDirectory
                border.color: wallpaperGridView.currentIndex === index ? Color.mHover : Color.mSurface
                border.width: Math.max(1, Style.borderL * 1.5)

                ColumnLayout {
                  anchors.centerIn: parent
                  spacing: Style.marginS

                  NIcon {
                    icon: "folder"
                    pointSize: Style.fontSizeXXXL
                    color: Color.mPrimary
                    Layout.alignment: Qt.AlignHCenter
                  }
                }
              }

              // Image display (for non-directories)
              NImageRounded {
                id: img
                anchors.left: parent.left
                anchors.right: parent.right
                anchors.top: parent.top
                height: imageContainer.imageHeight
                visible: !wallpaperItem.isDirectory
                imagePath: wallpaperItem.cachedPath
                radius: Style.radiusM
                borderColor: {
                  if (wallpaperItem.isSelected) {
                    return Color.mSecondary;
                  }
                  if (wallpaperGridView.currentIndex === index) {
                    return Color.mHover;
                  }
                  return Color.mSurface;
                }
                borderWidth: Math.max(1, Style.borderL * 1.5)
                imageFillMode: Image.PreserveAspectCrop
              }

              // Loading/error state background (for non-directories)
              Rectangle {
                anchors.left: parent.left
                anchors.right: parent.right
                anchors.top: parent.top
                height: imageContainer.imageHeight
                color: Color.mSurfaceVariant
                radius: Style.radiusM
                visible: !wallpaperItem.isDirectory && (img.status === Image.Loading || img.status === Image.Error || wallpaperItem.cachedPath === "")

                NIcon {
                  icon: "image"
                  pointSize: Style.fontSizeL
                  color: Color.mOnSurfaceVariant
                  anchors.centerIn: parent
                }
              }

              NBusyIndicator {
                anchors.horizontalCenter: parent.horizontalCenter
                y: (imageContainer.imageHeight - height) / 2
                visible: !wallpaperItem.isDirectory && (img.status === Image.Loading || wallpaperItem.cachedPath === "")
                running: visible
                size: 18
              }

              Rectangle {
                anchors.top: parent.top
                anchors.right: parent.right
                anchors.margins: Style.marginS
                width: 28
                height: 28
                radius: width / 2
                z: 6
                color: Color.mSecondary
                border.color: Color.mOutline
                border.width: Style.borderS
                visible: wallpaperItem.isSelected

                NIcon {
                  icon: "check"
                  pointSize: Style.fontSizeM
                  color: Color.mOnSecondary
                  anchors.centerIn: parent
                }

                MouseArea {
                  anchors.fill: parent
                  onClicked: {}
                }
              }

              // Favorite star button (top-left)
              Rectangle {
                anchors.top: parent.top
                anchors.left: parent.left
                anchors.margins: Style.marginS
                width: 28
                height: 28
                radius: width / 2
                visible: !wallpaperItem.isDirectory && (wallpaperItem.isFavorited || hoverHandler.hovered || wallpaperGridView.currentIndex === index)
                color: {
                  if (wallpaperItem.isFavorited)
                    return starHoverHandler.hovered ? Color.mHover : Color.mPrimary;
                  return starHoverHandler.hovered ? Color.mSurfaceVariant : Color.mSurface;
                }
                opacity: wallpaperItem.isFavorited || starHoverHandler.hovered ? 1.0 : 0.7
                z: 11

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

                NIcon {
                  icon: wallpaperItem.isFavorited ? "star-filled" : "star"
                  pointSize: Style.fontSizeM
                  color: {
                    if (wallpaperItem.isFavorited)
                      return starHoverHandler.hovered ? Color.mOnHover : Color.mOnPrimary;
                    return starHoverHandler.hovered ? Color.mOnSurface : Color.mOnSurfaceVariant;
                  }
                  anchors.centerIn: parent
                }

                HoverHandler {
                  id: starHoverHandler
                }

                TapHandler {
                  onTapped: {
                    var mon = Settings.data.wallpaper.setWallpaperOnAllMonitors ? undefined : (wallpaperScreenView.targetScreen ? wallpaperScreenView.targetScreen.name : undefined);
                    WallpaperService.toggleFavorite(wallpaperItem.wallpaperPath, WallpaperService.wallpaperSelectionAppearance, mon);
                  }
                }
              }

              // Palette color dots (bottom-center, favorites only) — taps must not fall through to selectItem
              Item {
                id: paletteRow
                anchors.bottom: img.bottom
                anchors.horizontalCenter: parent.horizontalCenter
                anchors.bottomMargin: Style.marginS
                z: 10
                implicitWidth: paletteRowRow.implicitWidth
                implicitHeight: paletteRowRow.implicitHeight
                width: implicitWidth
                height: implicitHeight
                visible: wallpaperItem.isFavorited && paletteRow.colors.length > 0

                property int diameter: 25 * Style.uiScaleRatio
                property int _favRevision: 0
                property var favData: {
                  _favRevision;
                  WallpaperService.favoritesRevision;
                  Settings.data.wallpaper.linkLightAndDarkWallpapers;
                  return WallpaperService.getFavoriteForDisplay(wallpaperItem.wallpaperPath);
                }
                property var colors: favData && favData.paletteColors ? favData.paletteColors : []
                property bool isDark: {
                  if (!favData) {
                    return false;
                  }
                  if (favData.appearance === "dark") {
                    return true;
                  }
                  if (favData.appearance === "light") {
                    return false;
                  }
                  return favData.darkMode === true;
                }

                Connections {
                  target: WallpaperService
                  function onFavoriteDataUpdated(path) {
                    if (path === wallpaperItem.wallpaperPath)
                      paletteRow._favRevision++;
                  }
                }

                Row {
                  id: paletteRowRow
                  spacing: Style.marginXS

                  // Sun/moon only when light/dark share one wallpaper (which appearance the favorite targets)
                  Rectangle {
                    width: paletteRow.diameter
                    height: paletteRow.diameter
                    radius: width * 0.5
                    visible: Settings.data.wallpaper.linkLightAndDarkWallpapers
                    color: Color.mSurface
                    border.color: Color.mShadow
                    border.width: Style.borderS

                    NIcon {
                      icon: paletteRow.isDark ? "moon" : "sun"
                      pointSize: parent.width * 0.45
                      color: Color.mOnSurface
                      anchors.centerIn: parent
                    }
                  }

                  Repeater {
                    model: paletteRow.colors

                    Rectangle {
                      width: paletteRow.diameter
                      height: paletteRow.diameter
                      radius: width * 0.5
                      color: modelData
                      border.color: Color.mShadow
                      border.width: Style.borderS
                    }
                  }
                }

                TapHandler {
                  onTapped: {}
                }
              }

              Rectangle {
                anchors.left: parent.left
                anchors.right: parent.right
                anchors.top: parent.top
                height: imageContainer.imageHeight
                color: Color.mSurface
                radius: Style.radiusM
                opacity: (hoverHandler.hovered || wallpaperItem.isSelected || wallpaperGridView.currentIndex === index) ? 0 : 0.3
                Behavior on opacity {
                  NumberAnimation {
                    duration: Style.animationFast
                  }
                }
              }

              HoverHandler {
                id: hoverHandler
              }

              TapHandler {
                onTapped: {
                  wallpaperGridView.forceActiveFocus();
                  wallpaperGridView.currentIndex = index;
                  selectItem(wallpaperItem.wallpaperPath, wallpaperItem.isDirectory);
                }
              }
            }

            NText {
              text: wallpaperItem.filename
              visible: !Settings.data.wallpaper.hideWallpaperFilenames
              color: (hoverHandler.hovered || wallpaperItem.isSelected || wallpaperGridView.currentIndex === index) ? Color.mOnSurface : Color.mOnSurfaceVariant
              pointSize: Style.fontSizeXS
              Layout.fillWidth: true
              Layout.leftMargin: Style.marginS
              Layout.rightMargin: Style.marginS
              Layout.alignment: Qt.AlignHCenter
              horizontalAlignment: Text.AlignHCenter
              elide: Text.ElideRight
            }
          }
        }
      }

      // Empty / scanning state
      Rectangle {
        color: Color.mSurface
        radius: Style.radiusM
        border.color: Color.mOutline
        border.width: Style.borderS
        visible: (wallpaperModel.count === 0 && !WallpaperService.scanning) || WallpaperService.scanning
        Layout.fillWidth: true
        Layout.preferredHeight: 130

        ColumnLayout {
          anchors.fill: parent
          visible: WallpaperService.scanning
          NBusyIndicator {
            Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
          }
        }

        ColumnLayout {
          anchors.fill: parent
          visible: wallpaperModel.count === 0 && !WallpaperService.scanning
          Item {
            Layout.fillHeight: true
          }
          NIcon {
            icon: "folder-open"
            pointSize: Style.fontSizeXXL
            color: Color.mOnSurface
            Layout.alignment: Qt.AlignHCenter
          }
          NText {
            text: (panelContent.filterText && panelContent.filterText.length > 0) ? I18n.tr("wallpaper.no-match") : (isBrowseMode ? I18n.tr("wallpaper.browse.empty-directory") : I18n.tr("wallpaper.no-wallpaper"))
            color: Color.mOnSurface
            font.weight: Style.fontWeightBold
            Layout.alignment: Qt.AlignHCenter
          }
          NText {
            text: (panelContent.filterText && panelContent.filterText.length > 0) ? I18n.tr("wallpaper.try-different-search") : (isBrowseMode ? I18n.tr("wallpaper.browse.go-up-hint") : I18n.tr("wallpaper.configure-directory"))
            color: Color.mOnSurfaceVariant
            wrapMode: Text.WordWrap
            Layout.alignment: Qt.AlignHCenter
          }
          Item {
            Layout.fillHeight: true
          }
        }
      }
    }
  }

  // Component for Wallhaven wallpapers view
  component WallhavenView: Item {
    id: wallhavenViewRoot
    property alias gridView: wallhavenGridView
    property alias pageInput: pageInput

    property var wallpapers: []
    property bool loading: false
    property string errorMessage: ""
    property bool initialized: false
    property bool searchScheduled: false

    Connections {
      target: typeof WallhavenService !== "undefined" ? WallhavenService : null
      function onSearchCompleted(results, meta) {
        wallhavenViewRoot.wallpapers = results || [];
        wallhavenViewRoot.loading = false;
        wallhavenViewRoot.errorMessage = "";
        wallhavenViewRoot.searchScheduled = false;
      }
      function onSearchFailed(error) {
        wallhavenViewRoot.loading = false;
        wallhavenViewRoot.errorMessage = error || "";
        wallhavenViewRoot.searchScheduled = false;
      }
    }

    Component.onCompleted: {
      // Initialize service properties and perform initial search if Wallhaven is active
      if (typeof WallhavenService !== "undefined" && Settings.data.wallpaper.useWallhaven && !initialized) {
        // Set flags immediately to prevent race conditions
        if (WallhavenService.initialSearchScheduled) {
          // Another instance already scheduled the search, just initialize properties
          initialized = true;
          return;
        }

        // We're the first one - claim the search
        initialized = true;
        WallhavenService.initialSearchScheduled = true;
        WallhavenService.categories = Settings.data.wallpaper.wallhavenCategories;
        WallhavenService.purity = Settings.data.wallpaper.wallhavenPurity;
        WallhavenService.sorting = Settings.data.wallpaper.wallhavenSorting;
        WallhavenService.order = Settings.data.wallpaper.wallhavenOrder;

        // Initialize resolution settings
        var width = Settings.data.wallpaper.wallhavenResolutionWidth || "";
        var height = Settings.data.wallpaper.wallhavenResolutionHeight || "";
        var mode = Settings.data.wallpaper.wallhavenResolutionMode || "atleast";
        if (width && height) {
          var resolution = width + "x" + height;
          if (mode === "atleast") {
            WallhavenService.minResolution = resolution;
            WallhavenService.resolutions = "";
          } else {
            WallhavenService.minResolution = "";
            WallhavenService.resolutions = resolution;
          }
        } else {
          WallhavenService.minResolution = "";
          WallhavenService.resolutions = "";
        }

        // Now check if we can actually search (fetching check is in WallhavenService.search)
        // Use persisted currentPage to maintain state across window reopening
        loading = true;
        WallhavenService.search(Settings.data.wallpaper.wallhavenQuery || "", WallhavenService.currentPage);
      }
    }

    ColumnLayout {
      anchors.fill: parent
      spacing: Style.marginM

      Item {
        Layout.fillWidth: true
        Layout.fillHeight: true

        NGridView {
          id: wallhavenGridView

          anchors.fill: parent

          visible: !loading && errorMessage === "" && (wallpapers && wallpapers.length > 0)
          interactive: true
          keyNavigationEnabled: true
          keyNavigationWraps: false
          highlightFollowsCurrentItem: false
          currentIndex: -1

          model: wallpapers || []

          onModelChanged: {
            // Reset selection and scroll position when model changes
            currentIndex = -1;
            positionViewAtBeginning();
          }

          Component.onCompleted: {
            positionViewAtBeginning();
          }

          property int columns: (screen.width > 1920) ? 5 : 4
          property int itemSize: cellWidth

          cellWidth: Math.floor((availableWidth - leftMargin - rightMargin) / columns)
          cellHeight: Math.floor(itemSize * 0.7) + Style.marginXS + Style.fontSizeXS + Style.marginM

          leftMargin: Style.marginS
          rightMargin: Style.marginS
          topMargin: Style.marginS
          bottomMargin: Style.marginS

          onCurrentIndexChanged: {
            if (currentIndex >= 0) {
              positionViewAtIndex(currentIndex, GridView.Contain);
            }
          }

          onKeyPressed: event => {
                          if (Keybinds.checkKey(event, 'enter', Settings)) {
                            if (currentIndex >= 0 && currentIndex < wallpapers.length) {
                              let wallpaper = wallpapers[currentIndex];
                              wallhavenDownloadAndApply(wallpaper);
                            }
                            event.accepted = true;
                          }
                        }

          delegate: Item {
            id: wallhavenItemWrapper
            width: wallhavenGridView.cellWidth
            height: wallhavenGridView.cellHeight

            ColumnLayout {
              id: wallhavenItem
              anchors.fill: parent
              anchors.margins: Style.marginXS

              property string thumbnailUrl: (modelData && typeof WallhavenService !== "undefined") ? WallhavenService.getThumbnailUrl(modelData, "large") : ""
              property string wallpaperId: (modelData && modelData.id) ? modelData.id : ""

              spacing: Style.marginXS

              Item {
                id: imageContainer
                Layout.fillWidth: true
                Layout.fillHeight: true

                property real imageHeight: Math.round(wallhavenGridView.itemSize * 0.67)

                NImageRounded {
                  id: img
                  anchors.left: parent.left
                  anchors.right: parent.right
                  anchors.top: parent.top
                  height: imageContainer.imageHeight
                  imagePath: wallhavenItem.thumbnailUrl
                  radius: Style.radiusM
                  borderColor: {
                    if (wallhavenGridView.currentIndex === index) {
                      return Color.mHover;
                    }
                    return Color.mSurface;
                  }
                  borderWidth: Math.max(1, Style.borderL * 1.5)
                  imageFillMode: Image.PreserveAspectCrop
                }

                // Loading/error state background
                Rectangle {
                  anchors.left: parent.left
                  anchors.right: parent.right
                  anchors.top: parent.top
                  height: imageContainer.imageHeight
                  color: Color.mSurfaceVariant
                  radius: Style.radiusM
                  visible: img.status === Image.Loading || img.status === Image.Error || wallhavenItem.thumbnailUrl === ""

                  NIcon {
                    icon: "image"
                    pointSize: Style.fontSizeL
                    color: Color.mOnSurfaceVariant
                    anchors.centerIn: parent
                  }
                }

                NBusyIndicator {
                  anchors.horizontalCenter: parent.horizontalCenter
                  y: (imageContainer.imageHeight - height) / 2
                  visible: img.status === Image.Loading
                  running: visible
                  size: 18
                }

                Rectangle {
                  anchors.left: parent.left
                  anchors.right: parent.right
                  anchors.top: parent.top
                  height: imageContainer.imageHeight
                  color: Color.mSurface
                  radius: Style.radiusM
                  opacity: (hoverHandler.hovered || wallhavenGridView.currentIndex === index) ? 0 : 0.3
                  Behavior on opacity {
                    NumberAnimation {
                      duration: Style.animationFast
                    }
                  }
                }

                HoverHandler {
                  id: hoverHandler
                }

                TapHandler {
                  onTapped: {
                    wallhavenGridView.forceActiveFocus();
                    wallhavenGridView.currentIndex = index;
                    wallhavenDownloadAndApply(modelData);
                  }
                }
              }

              NText {
                text: wallhavenItem.wallpaperId || I18n.tr("common.unknown")
                visible: !Settings.data.wallpaper.hideWallpaperFilenames
                color: (hoverHandler.hovered || wallhavenGridView.currentIndex === index) ? Color.mOnSurface : Color.mOnSurfaceVariant
                pointSize: Style.fontSizeXS
                Layout.fillWidth: true
                Layout.leftMargin: Style.marginS
                Layout.rightMargin: Style.marginS
                Layout.alignment: Qt.AlignHCenter
                horizontalAlignment: Text.AlignHCenter
                elide: Text.ElideRight
              }
            }
          }
        }

        // Loading overlay - fills same space as GridView to prevent jumping
        Rectangle {
          anchors.fill: parent
          color: Color.mSurface
          radius: Style.radiusM
          border.color: Color.mOutline
          border.width: Style.borderS
          visible: loading || (typeof WallhavenService !== "undefined" && WallhavenService.fetching)
          z: 10

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

            Item {
              Layout.fillHeight: true
            }

            NBusyIndicator {
              size: Style.baseWidgetSize * 1.5
              color: Color.mPrimary
              Layout.alignment: Qt.AlignHCenter
            }

            NText {
              text: I18n.tr("wallpaper.wallhaven.loading")
              color: Color.mOnSurfaceVariant
              pointSize: Style.fontSizeM
              Layout.alignment: Qt.AlignHCenter
            }

            Item {
              Layout.fillHeight: true
            }
          }
        }

        // Error overlay
        Rectangle {
          anchors.fill: parent
          color: Color.mSurface
          radius: Style.radiusM
          border.color: Color.mOutline
          border.width: Style.borderS
          visible: errorMessage !== "" && !loading
          z: 10

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

            Item {
              Layout.fillHeight: true
            }

            NIcon {
              icon: "alert-circle"
              pointSize: Style.fontSizeXXL
              color: Color.mError
              Layout.alignment: Qt.AlignHCenter
            }

            NText {
              text: errorMessage
              color: Color.mOnSurface
              wrapMode: Text.WordWrap
              Layout.alignment: Qt.AlignHCenter
              Layout.fillWidth: true
              horizontalAlignment: Text.AlignHCenter
            }

            Item {
              Layout.fillHeight: true
            }
          }
        }

        // Empty state overlay
        Rectangle {
          anchors.fill: parent
          color: Color.mSurface
          radius: Style.radiusM
          border.color: Color.mOutline
          border.width: Style.borderS
          visible: (!wallpapers || wallpapers.length === 0) && !loading && errorMessage === ""
          z: 10

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

            Item {
              Layout.fillHeight: true
            }

            NIcon {
              icon: "image"
              pointSize: Style.fontSizeXXL
              color: Color.mOnSurfaceVariant
              Layout.alignment: Qt.AlignHCenter
            }

            NText {
              text: I18n.tr("wallpaper.wallhaven.no-results")
              color: Color.mOnSurface
              wrapMode: Text.WordWrap
              Layout.alignment: Qt.AlignHCenter
              Layout.fillWidth: true
              horizontalAlignment: Text.AlignHCenter
            }

            Item {
              Layout.fillHeight: true
            }
          }
        }
      }

      // Pagination
      RowLayout {
        Layout.fillWidth: true
        visible: errorMessage === "" && typeof WallhavenService !== "undefined"
        spacing: Style.marginS

        Item {
          Layout.fillWidth: true
        }

        NIconButton {
          icon: "chevron-left"
          enabled: !loading && WallhavenService.currentPage > 1 && !WallhavenService.fetching
          onClicked: WallhavenService.previousPage()
        }

        RowLayout {
          spacing: Style.marginXS

          NText {
            text: I18n.tr("wallpaper.wallhaven.page-prefix")
            color: Color.mOnSurface
          }

          NTextInput {
            id: pageInput
            text: "" + WallhavenService.currentPage
            Layout.preferredWidth: 50 * Style.uiScaleRatio
            Layout.maximumWidth: 50 * Style.uiScaleRatio
            Layout.fillWidth: false
            minimumInputWidth: 50 * Style.uiScaleRatio
            horizontalAlignment: Text.AlignHCenter
            inputMethodHints: Qt.ImhDigitsOnly
            enabled: !loading && !WallhavenService.fetching
            showClearButton: false

            Connections {
              target: WallhavenService
              function onCurrentPageChanged() {
                pageInput.text = "" + WallhavenService.currentPage;
              }
            }

            function submitPage() {
              var page = parseInt(text);
              if (!isNaN(page) && page >= 1 && page <= WallhavenService.lastPage) {
                if (page !== WallhavenService.currentPage) {
                  WallhavenService.search(Settings.data.wallpaper.wallhavenQuery || "", page);
                }
              } else {
                // Reset to current page if invalid
                text = "" + WallhavenService.currentPage;
              }
              // Force focus loss to ensure UI updates cleanly
              pageInput.inputItem.focus = false;
            }

            onEditingFinished: submitPage()
          }

          NText {
            text: I18n.tr("wallpaper.wallhaven.page-suffix").replace("{total}", WallhavenService.lastPage)
            color: Color.mOnSurface
          }
        }

        NIconButton {
          icon: "chevron-right"
          enabled: WallhavenService.currentPage < WallhavenService.lastPage && !WallhavenService.fetching
          onClicked: WallhavenService.nextPage()
        }

        Item {
          Layout.fillWidth: true
        }
      }
    }

    // -------------------------------
    function wallhavenDownloadAndApply(wallpaper, targetScreen) {
      if (typeof WallhavenService !== "undefined") {
        WallhavenService.downloadWallpaper(wallpaper, function (success, localPath) {
          if (success) {
            var whScreen = Settings.data.wallpaper.setWallpaperOnAllMonitors ? undefined : Quickshell.screens[currentScreenIndex].name;
            if (!Settings.data.wallpaper.setWallpaperOnAllMonitors && currentScreenIndex < Quickshell.screens.length) {
              WallpaperService.changeWallpaper(localPath, Quickshell.screens[currentScreenIndex].name, WallpaperService.wallpaperSelectionAppearance);
            } else {
              WallpaperService.changeWallpaper(localPath, undefined, WallpaperService.wallpaperSelectionAppearance);
            }
            WallpaperService.applyFavoriteTheme(localPath, whScreen, WallpaperService.wallpaperSelectionAppearance);
          }
        });
      }
    }
  }
}
