import QtQuick
import QtQuick.Effects
import QtQuick.Layouts
import QtQuick.Controls
import Quickshell
import Quickshell.Services.SystemTray
import Quickshell.Widgets
import qs.Commons
import qs.Modules.Bar.Extras
import qs.Services.UI
import qs.Widgets

Rectangle {
  id: root

  property ShellScreen screen

  // Widget properties passed from Bar.qml for per-instance settings
  property string widgetId: ""
  property string section: ""
  property int sectionWidgetIndex: -1
  property int sectionWidgetsCount: 0

  property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
  property var widgetSettings: {
    if (section && sectionWidgetIndex >= 0) {
      var widgets = Settings.data.bar.widgets[section]
      if (widgets && sectionWidgetIndex < widgets.length) {
        return widgets[sectionWidgetIndex]
      }
    }
    return {}
  }

  readonly property string barPosition: Settings.data.bar.position
  readonly property bool isVertical: barPosition === "left" || barPosition === "right"
  readonly property bool density: Settings.data.bar.density
  readonly property real iconSize: Math.round(Style.capsuleHeight * 0.65)

  property list<string> blacklist: widgetSettings.blacklist || widgetMetadata.blacklist || [] // Read from settings
  property list<string> favorites: widgetSettings.favorites || widgetMetadata.favorites || [] // Pinned items (shown inline)
  property bool drawerEnabled: widgetSettings.drawerEnabled !== undefined ? widgetSettings.drawerEnabled : (widgetMetadata.drawerEnabled !== undefined ? widgetMetadata.drawerEnabled : true) // Enable drawer panel
  property var filteredItems: [] // Items to show inline (pinned/favorites)
  property var dropdownItems: [] // Items to show in drawer (unpinned/non-favorites)

  // Debounce timer for updateFilteredItems to prevent excessive calls
  // when multiple events (e.g., SystemTray changes, settings saves)
  // trigger it in rapid succession, reducing redundant processing.
  Timer {
    id: updateDebounceTimer
    interval: 100 // milliseconds
    running: false
    repeat: false
    onTriggered: _performFilteredItemsUpdate()
  }

  function _performFilteredItemsUpdate() {
    let newItems = []
    if (SystemTray.items && SystemTray.items.values) {
      const trayItems = SystemTray.items.values
      for (var i = 0; i < trayItems.length; i++) {
        const item = trayItems[i]
        if (!item) {
          continue
        }

        const title = item.tooltipTitle || item.name || item.id || ""

        // Check if blacklisted
        let isBlacklisted = false
        if (root.blacklist && root.blacklist.length > 0) {
          for (var j = 0; j < root.blacklist.length; j++) {
            const rule = root.blacklist[j]
            if (wildCardMatch(title, rule)) {
              isBlacklisted = true
              break
            }
          }
        }

        if (!isBlacklisted) {
          newItems.push(item)
        }
      }
    }

    // If drawer is disabled, show all items inline
    if (!root.drawerEnabled) {
      filteredItems = newItems
      dropdownItems = []
    } else {
      // Build inline (pinned/favorites) and drawer (unpinned/non-favorites) lists
      // If favorites list is empty, all items go to drawer (none inline)
      // If favorites list has items, favorites are inline, rest go to drawer
      if (favorites && favorites.length > 0) {
        let fav = []
        for (var k = 0; k < newItems.length; k++) {
          const item2 = newItems[k]
          const title2 = item2.tooltipTitle || item2.name || item2.id || ""
          for (var m = 0; m < favorites.length; m++) {
            const rule2 = favorites[m]
            if (wildCardMatch(title2, rule2)) {
              fav.push(item2)
              break
            }
          }
        }
        filteredItems = fav

        // Non-favorites (unpinned) go to drawer
        let nonFav = []
        for (var v = 0; v < newItems.length; v++) {
          const cand = newItems[v]
          let isFavorite = false
          for (var f = 0; f < filteredItems.length; f++) {
            if (filteredItems[f] === cand) {
              isFavorite = true
              break
            }
          }
          if (!isFavorite)
            nonFav.push(cand)
        }
        dropdownItems = nonFav
      } else {
        // No favorites (pinned): all items go to drawer (none inline)
        filteredItems = []
        dropdownItems = newItems
      }
    }
  }

  function updateFilteredItems() {
    updateDebounceTimer.restart()
  }

  function wildCardMatch(str, rule) {
    if (!str || !rule) {
      return false
    }
    //Logger.d("Tray", "wildCardMatch - Input str:", str, "rule:", rule)

    // Escape all special regex characters in the rule
    let escapedRule = rule.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
    // Convert '*' to '.*' for wildcard matching
    let pattern = escapedRule.replace(/\\\*/g, '.*')
    // Add ^ and $ to match the entire string
    pattern = '^' + pattern + '$'

    //Logger.d("Tray", "wildCardMatch - Generated pattern:", pattern)
    try {
      const regex = new RegExp(pattern, 'i')
      // 'i' for case-insensitive
      //Logger.d("Tray", "wildCardMatch - Regex test result:", regex.test(str))
      return regex.test(str)
    } catch (e) {
      Logger.w("Tray", "Invalid regex pattern for wildcard match:", rule, e.message)
      return false // If regex is invalid, it won't match
    }
  }

  function toggleDrawer(button) {
    TooltipService.hideImmediately()
    const panel = PanelService.getPanel("trayDrawerPanel", root.screen)
    if (panel) {
      panel.widgetSection = root.section
      panel.widgetIndex = root.sectionWidgetIndex
      panel.toggle(this)
    }
  }

  Connections {
    target: SystemTray.items
    function onValuesChanged() {
      root.updateFilteredItems()
    }
  }

  Connections {
    target: Settings
    function onSettingsSaved() {
      root.updateFilteredItems()
    }
  }

  Component.onCompleted: {
    root.updateFilteredItems() // Initial update
  }

  visible: filteredItems.length > 0 || dropdownItems.length > 0
  implicitWidth: isVertical ? Style.capsuleHeight : Math.round(trayFlow.implicitWidth)
  implicitHeight: isVertical ? Math.round(trayFlow.implicitHeight) : Style.capsuleHeight
  radius: Style.radiusM
  color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent

  Flow {
    id: trayFlow
    spacing: Style.marginXS
    flow: isVertical ? Flow.TopToBottom : Flow.LeftToRight

    // Drawer opener (before items if opposite direction)
    NIconButton {
      id: chevronIconBefore
      visible: root.drawerEnabled && dropdownItems.length > 0 && BarService.getPillDirection(root)
      tooltipText: I18n.tr("tooltips.open-tray-dropdown")
      tooltipDirection: BarService.getTooltipDirection()
      density: Settings.data.bar.density
      baseSize: Style.capsuleHeight
      applyUiScale: false
      colorBg: Settings.data.colorSchemes.darkMode ? (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) : Color.mPrimary
      colorFg: Settings.data.colorSchemes.darkMode ? Color.mOnSurface : Color.mOnPrimary
      colorBorder: Color.transparent
      colorBorderHover: Color.transparent
      icon: {
        switch (barPosition) {
        case "bottom":
          return "caret-up"
        case "left":
          return "caret-right"
        case "right":
          return "caret-left"
        case "top":
        default:
          return "caret-down"
        }
      }
      onClicked: toggleDrawer(this)
      onRightClicked: toggleDrawer(this)
    }

    Repeater {
      id: repeater
      model: root.filteredItems

      delegate: Item {
        width: Style.capsuleHeight
        height: Style.capsuleHeight
        visible: modelData

        IconImage {
          id: trayIcon
          width: iconSize
          height: iconSize
          anchors.centerIn: parent
          asynchronous: true
          backer.fillMode: Image.PreserveAspectFit

          property bool menuJustOpened: false

          source: {
            let icon = modelData?.icon || ""
            if (!icon) {
              return ""
            }

            // Process icon path
            if (icon.includes("?path=")) {
              const chunks = icon.split("?path=")
              const name = chunks[0]
              const path = chunks[1]
              const fileName = name.substring(name.lastIndexOf("/") + 1)
              return `file://${path}/${fileName}`
            }
            return icon
          }
          opacity: status === Image.Ready ? 1 : 0

          layer.enabled: widgetSettings.colorizeIcons !== false
          layer.effect: ShaderEffect {
            property color targetColor: Settings.data.colorSchemes.darkMode ? Color.mOnSurface : Color.mSurfaceVariant
            property real colorizeMode: 1.0

            fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/appicon_colorize.frag.qsb")
          }

          MouseArea {
            anchors.fill: parent
            hoverEnabled: true
            cursorShape: Qt.PointingHandCursor
            acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
            onClicked: mouse => {
                         if (!modelData) {
                           return
                         }

                         if (mouse.button === Qt.LeftButton) {
                           // Close any open menu first
                           PanelService.getPanel("trayMenuPanel", root.screen)?.close()

                           if (!modelData.onlyMenu) {
                             modelData.activate()
                           }
                         } else if (mouse.button === Qt.MiddleButton) {
                           // Close any open menu first
                           PanelService.getPanel("trayMenuPanel", root.screen)?.close()

                           modelData.secondaryActivate && modelData.secondaryActivate()
                         } else if (mouse.button === Qt.RightButton) {
                           TooltipService.hideImmediately()

                           // Close the menu if it was visible
                           const menuPanel = PanelService.getPanel("trayMenuPanel", root.screen)
                           if (menuPanel && menuPanel.visible) {
                             menuPanel.close()
                             return
                           }

                           if (modelData.hasMenu && modelData.menu) {
                             const panel = PanelService.getPanel("trayMenuPanel", root.screen)
                             if (panel) {
                               panel.menu = modelData.menu
                               panel.trayItem = modelData
                               panel.widgetSection = root.section
                               panel.widgetIndex = root.sectionWidgetIndex
                               panel.openAt(parent)
                               // Prevent onEntered from immediately closing the panel
                               trayIcon.menuJustOpened = true
                             } else {
                               Logger.i("Tray", "TrayMenu not available")
                             }
                           } else {
                             Logger.i("Tray", "No menu available for", modelData.id, "or trayMenu not set")
                           }
                         }
                       }
            onEntered: {
              // Don't close menu immediately after opening it
              if (!trayIcon.menuJustOpened) {
                // Only close the menu if we're hovering over a DIFFERENT tray icon
                const menuPanel = PanelService.getPanel("trayMenuPanel", root.screen)
                if (menuPanel && menuPanel.trayItem !== modelData) {
                  menuPanel.close()
                }
              }
              trayIcon.menuJustOpened = false
              TooltipService.show(Screen, trayIcon, modelData.tooltipTitle || modelData.name || modelData.id || "Tray Item", BarService.getTooltipDirection())
            }
            onExited: TooltipService.hide()
          }
        }
      }
    }

    // Drawer opener (after items if normal direction)
    NIconButton {
      id: chevronIconAfter
      visible: root.drawerEnabled && dropdownItems.length > 0 && !BarService.getPillDirection(root)
      tooltipText: I18n.tr("tooltips.open-tray-dropdown")
      tooltipDirection: BarService.getTooltipDirection()
      density: Settings.data.bar.density
      baseSize: Style.capsuleHeight
      applyUiScale: false
      colorBg: Settings.data.colorSchemes.darkMode ? (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) : Color.mPrimary
      colorFg: Settings.data.colorSchemes.darkMode ? Color.mOnSurface : Color.mOnPrimary
      colorBorder: Color.transparent
      colorBorderHover: Color.transparent
      icon: {
        switch (barPosition) {
        case "bottom":
          return "caret-up"
        case "left":
          return "caret-right"
        case "right":
          return "caret-left"
        case "top":
        default:
          return "caret-down"
        }
      }
      onClicked: toggleDrawer(this)
      onRightClicked: toggleDrawer(this)
    }
  }
}
