import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Services.Pipewire
import qs.Commons
import qs.Modules.Bar.Extras
import qs.Services.UI
import qs.Widgets

Item {
  id: root

  property var pluginApi: null

  property ShellScreen screen
  property string widgetId: ""
  property string section: ""

  // Bar positioning properties
  readonly property string screenName: screen ? screen.name : ""
  readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
  readonly property bool isVertical: barPosition === "left" || barPosition === "right"
  readonly property real barHeight: Style.getBarHeightForScreen(screenName)
  readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screenName)
  readonly property real barFontSize: Style.getBarFontSizeForScreen(screenName)

  property bool micActive: false
  property bool camActive: false
  property bool scrActive: false
  property var micApps: []
  property var camApps: []
  property var scrApps: []

  property var cfg: pluginApi?.pluginSettings || ({})
  property var defaults: pluginApi?.manifest?.metadata?.defaultSettings || ({})

  property bool hideInactive: cfg.hideInactive ?? defaults.hideInactive
  property bool removeMargins: cfg.removeMargins ?? defaults.removeMargins
  property int iconSpacing: cfg.iconSpacing || Style.marginXS

  property string activeColorKey: cfg.activeColor ?? defaults.activeColor
  property string inactiveColorKey: cfg.inactiveColor ?? defaults.inactiveColor

  readonly property color activeColor: Color.resolveColorKey(activeColorKey)
  readonly property color inactiveColor: inactiveColorKey === "none" ? Qt.alpha(Color.mOnSurfaceVariant, 0.3) : Color.resolveColorKey(inactiveColorKey)
  readonly property color micColor: micActive ? activeColor : inactiveColor
  readonly property color camColor: camActive ? activeColor : inactiveColor
  readonly property color scrColor: scrActive ? activeColor : inactiveColor

  readonly property bool isVisible: !hideInactive || micActive || camActive || scrActive

  property real margins: removeMargins ? 0 : Style.marginM * 2

  readonly property real contentWidth: isVertical ? Style.capsuleHeight : Math.round(layout.implicitWidth + margins)
  readonly property real contentHeight: isVertical ? Math.round(layout.implicitHeight + margins) : Style.capsuleHeight

  implicitWidth: contentWidth
  implicitHeight: contentHeight

  Layout.alignment: Qt.AlignVCenter
  visible: root.isVisible
  opacity: root.isVisible ? 1.0 : 0.0

  PwObjectTracker {
    objects: Pipewire.ready ? Pipewire.nodes.values : []
  }

  Process {
    id: cameraCheckProcess
    running: false

    command: ["sh", "-c", "for dev in /dev/video*; do [ -e \"$dev\" ] && [ -n \"$(find /proc/[0-9]*/fd/ -lname \"$dev\" 2>/dev/null | head -n1)\" ] && echo \"active\" && exit 0; done; exit 1"]

    onExited: (code, status) => {
      var isActive = code === 0;
      root.camActive = isActive;

      if (isActive) {
        cameraAppsProcess.running = true;
      } else {
        root.camApps = [];
      }
    }
  }

  Process {
    id: cameraAppsProcess
    running: false

    command: ["sh", "-c", "for dev in /dev/video*; do [ -e \"$dev\" ] && for fd in /proc/[0-9]*/fd/*; do [ -L \"$fd\" ] && [ \"$(readlink \"$fd\" 2>/dev/null)\" = \"$dev\" ] && ps -p \"$(echo \"$fd\" | cut -d/ -f3)\" -o comm= 2>/dev/null; done; done | sort -u | tr '\\n' ',' | sed 's/,$//'"]

    onExited: (code, status) => {
      if (stdout) {
        var appsString = stdout.trim();
        var apps = appsString.length > 0 ? appsString.split(',') : [];
        root.camApps = apps;
      } else {
        root.camApps = [];
      }
    }
  }

  Timer {
    interval: 1000
    repeat: true
    running: true
    triggeredOnStart: true
    onTriggered: updatePrivacyState()
  }

  function hasNodeLinks(node, links) {
    for (var i = 0; i < links.length; i++) {
      var link = links[i];
      if (link && (link.source === node || link.target === node)) {
        return true;
      }
    }
    return false;
  }

  function getAppName(node) {
    return node.properties["application.name"] || node.nickname || node.name || "";
  }

  function updateMicrophoneState(nodes, links) {
    var appNames = [];
    var isActive = false;

    for (var i = 0; i < nodes.length; i++) {
      var node = nodes[i];
      if (!node || !node.isStream || !node.audio || node.isSink) continue;
      if (!hasNodeLinks(node, links) || !node.properties) continue;

      var mediaClass = node.properties["media.class"] || "";
      if (mediaClass === "Stream/Input/Audio") {
        if (node.properties["stream.capture.sink"] === "true") {
          continue;
        }

        isActive = true;
        var appName = getAppName(node);
        if (appName && appNames.indexOf(appName) === -1) {
          appNames.push(appName);
        }
      }
    }

    root.micActive = isActive;
    root.micApps = appNames;
  }

  function updateCameraState() {
    cameraCheckProcess.running = true;
  }

  function isScreenShareNode(node) {
    if (!node.properties) {
      return false;
    }

    var mediaClass = node.properties["media.class"] || "";

    if (mediaClass.indexOf("Audio") >= 0) {
      return false;
    }

    if (mediaClass.indexOf("Video") === -1) {
      return false;
    }

    var mediaName = (node.properties["media.name"] || "").toLowerCase();

    if (mediaName.match(/^(xdph-streaming|gsr-default|game capture|screen|desktop|display|cast|webrtc|v4l2)/) ||
        mediaName === "gsr-default_output" ||
        mediaName.match(/screen-cast|screen-capture|desktop-capture|monitor-capture|window-capture|game-capture/i)) {
      return true;
    }

    return false;
  }

  function updateScreenShareState(nodes, links) {
    var appNames = [];
    var isActive = false;

    for (var i = 0; i < nodes.length; i++) {
      var node = nodes[i];
      if (!node || !hasNodeLinks(node, links) || !node.properties) continue;

      if (isScreenShareNode(node)) {
        isActive = true;
        var appName = getAppName(node);
        if (appName && appNames.indexOf(appName) === -1) {
          appNames.push(appName);
        }
      }
    }

    root.scrActive = isActive;
    root.scrApps = appNames;
  }

  function updatePrivacyState() {
    if (!Pipewire.ready) return;

    var nodes = Pipewire.nodes.values || [];
    var links = Pipewire.links.values || [];

    updateMicrophoneState(nodes, links);
    updateCameraState();
    updateScreenShareState(nodes, links);
  }

  function buildTooltip() {
    var parts = [];

    if (micActive && micApps.length > 0) {
      parts.push("Mic: " + micApps.join(", "));
    }

    if (camActive && camApps.length > 0) {
      parts.push("Cam: " + camApps.join(", "));
    }

    if (scrActive && scrApps.length > 0) {
      parts.push("Screen sharing: " + scrApps.join(", "));
    }

    return parts.length > 0 ? parts.join("\n") : "";
  }

  Rectangle {
    id: visualCapsule
    x: Style.pixelAlignCenter(parent.width, width)
    y: Style.pixelAlignCenter(parent.height, height)
    width: root.contentWidth
    height: root.contentHeight
    radius: Style.radiusM
    color: Style.capsuleColor
    border.color: Style.capsuleBorderColor
    border.width: Style.capsuleBorderWidth

    Item {
      id: layout

      anchors.verticalCenter: parent.verticalCenter
      anchors.horizontalCenter: parent.horizontalCenter

      implicitWidth: iconsLayout.implicitWidth
      implicitHeight: iconsLayout.implicitHeight

      GridLayout {
        id: iconsLayout

        columns: root.isVertical ? 1 : 3
        rows: root.isVertical ? 3 : 1

        rowSpacing: root.iconSpacing
        columnSpacing: root.iconSpacing

        NIcon {
          visible: micActive || !root.hideInactive
          icon: micActive ? "microphone" : "microphone-off"
          color: root.micColor
        }
        NIcon {
          visible: camActive || !root.hideInactive
          icon: camActive ? "camera" : "camera-off"
          color: root.camColor
        }
        NIcon {
          visible: scrActive || !root.hideInactive
          icon: scrActive ? "screen-share" : "screen-share-off"
          color: root.scrColor
        }
      }
    }
  }

  NPopupContextMenu {
    id: contextMenu

    model: [
      {
        "label": pluginApi?.tr("menu.settings"),
        "action": "settings",
        "icon": "settings"
      },
    ]

    onTriggered: function (action) {
      contextMenu.close();
      PanelService.closeContextMenu(screen);
      if (action === "settings") {
        BarService.openPluginSettings(root.screen, pluginApi.manifest);
      }
    }
  }

  MouseArea {
    anchors.fill: parent
    acceptedButtons: Qt.RightButton
    hoverEnabled: true

    onClicked: function (mouse) {
      if (mouse.button === Qt.RightButton) {
        PanelService.showContextMenu(contextMenu, root, screen);
      }
    }

    onEntered: {
      var tooltipText = buildTooltip();
      if (tooltipText) {
        TooltipService.show(root, tooltipText, BarService.getTooltipDirection());
      }
    }
    onExited: TooltipService.hide()
  }
}
